---
title: "File System Operations"
method: POST
path: "/v3/fs"
tags: ["File System"]
---

# File System Operations

`POST /v3/fs`

**Navigate parsed documents and the cross-doc memory store via Unix-shell verbs.**

`POST /v3/fs` is a single op-driven endpoint that lets an LLM agent
(or any programmatic client) walk a corpus the way it would walk a
filesystem — `ls` to list, `cat` to read, `grep` to search, `head`
for a quick peek, `stat` for metadata, and `find` / `open` / `xref`
for the cross-doc entity memory layer.

The body always carries an `op` field; other fields apply per op.
The response envelope is uniform: `{op, data, hasMore?, nextCursor?, count?, hint?}`.

## Quick reference

| Op | `path` | Other fields | What it does |
|----|--------|-------------|--------------|
| `ls` | — | `filter`, `limit`, `cursor` | List parsed documents |
| `grep` | referenceID *(optional)* | `pattern`, `scope`, `countOnly` | Search across documents |
| `cat` | referenceID | `range`, `select` | Read a document's parsed content |
| `head` | referenceID | `n` | First N sections (default 10) |
| `stat` | referenceID *or* entityID | — | Metadata only |
| `find` | — | `filter`, `limit`, `cursor` | List canonical entities |
| `open` | entityID | — | Entity detail + all mentions |
| `xref` | entityID | `limit`, `cursor` | Sections across docs mentioning an entity |

**`path`** is the positional identifier. For doc ops (`cat`, `head`,
`stat`), pass a `referenceID` from `ls`. For entity ops (`open`,
`xref`), pass an `entityID` from `find`. `grep` optionally takes a
`path` to scope search to one document.

## Examples

**List documents:**
`{"op": "ls"}`

**Search one document:**
`{"op": "grep", "path": "my-doc-001", "pattern": "holiday", "scope": "sections"}`

**Read one page:**
`{"op": "cat", "path": "my-doc-001", "range": {"page": 7}}`

**Read a page range:**
`{"op": "cat", "path": "my-doc-001", "range": {"pageRange": [5, 10]}}`

**Project section labels and pages only:**
`{"op": "cat", "path": "my-doc-001", "select": ["sections.label", "sections.page", "sections.type"]}`

**Preview first 5 sections:**
`{"op": "head", "path": "my-doc-001", "n": 5}`

**Document metadata:**
`{"op": "stat", "path": "my-doc-001"}`

**List entities:**
`{"op": "find"}`

**Entity detail + mentions:**
`{"op": "open", "path": "ent_abc123"}`

**Cross-document sections for an entity:**
`{"op": "xref", "path": "ent_abc123"}`

## Key details

`range` is an **object** with optional keys: `page` (integer),
`pageRange` (two-element array `[from, to]`), `sectionTypes`
(array of strings like `["table", "heading"]`).

`select` is an **array of strings** — dotted paths like
`["sections.label", "sections.page"]`.

`scope` (grep) is one of `"sections"`, `"entities"`,
`"relationships"`, or `"all"` (default).

## Pagination

List ops (`ls`, `find`) paginate by cursor: pass the last item's
`nextCursor` from a previous response to fetch the next page;
`hasMore: false` signals the last page. Same idiom as `/v3/calls`
and `/v3/outputs`.

## Request body

- FSRequest — Request body for `POST /v3/fs`. Op-specific fields apply per op.
  - `op` 'ls' | 'find' | 'open' | 'cat' | 'grep' | 'xref' | 'stat' | 'head', required — Operations exposed by `POST /v3/fs`. The verbs and their flag names mirror Unix tools so an LLM agent's existing vocabulary maps directly: - `ls` — list parsed documents - `cat` — read one parsed doc (optionally sliced by range / projected by select) - `grep` — substring or regex search across parse outputs - `head` — first N sections of one doc - `stat` — metadata only (page count, section count, parsed at, ...) - `find` — list canonical entities (cross-doc memory) - `open` — entity + mentions - `xref` — entity → sections across docs that mention it Doc-level ops (ls, cat, grep, head, stat) work on every parsed document, regardless of how the parse function was configured. Memory-level ops (find, open, xref) operate on the global entities table which is only populated when the parse function had `linkAcrossDocuments: true`. On environments with no memory-linked docs they return empty data with a hint pointing at the toggle.
  - `context` FSContext — Request-scoping concerns that are orthogonal to the op itself. Carried on a `context` object so future scoping hints (e.g. as-of timestamps, read consistency) can slot in without reshaping the op-specific fields.
    - `bucket` string — Bucket KSUID (prefix `bkt_`) to scope the request to — a named partition of the knowledge graph within the caller's account+environment. **Optional.** Omitting it (or passing an empty value) leaves the request UNSCOPED: memory-level reads (`find` / `open` / `xref`) return entities across every bucket in the account+environment, so pre-bucket callers keep their original all-entities behavior unchanged. (Writes are different: a parse call with no bucket targets the account default bucket.) When a bucket IS supplied, memory-level ops return only entities in that bucket; doc-level ops (`ls`/`cat`/`head`/`stat`/`grep`) are unaffected either way — documents are not bucket-partitioned. A bucket that does not belong to the caller's account+environment is rejected.
  - `path` string — Identifier for ops that operate on a single resource: - cat / head / stat: a parsed document, by `referenceID` or `transformationID`. - open / xref / stat: an entity, by `entityID`.
  - `pattern` string — Substring or regex pattern for `op=grep`.
  - `regex` boolean — When true, `pattern` is interpreted as a Go regex. Default false.
  - `ignoreCase` boolean — When true (default), substring/regex matching is case-insensitive.
  - `scope` string — Restricts grep to one part of the parse output. One of `"sections"`, `"entities"`, `"relationships"`, `"all"` (default).
  - `countOnly` boolean — When true, return only the hit count without snippet payload. Cheaper than fetching matches when the agent only wants a yes/no.
  - `filter` FSFilter — Filter options for `op=ls` and `op=find`.
    - `type` string — Match an entity's `type` field exactly (e.g. `"drug"`, `"study"`).
    - `search` string — Substring match on canonical name (entities) or `referenceID` (parsed docs). Case-insensitive.
    - `functionName` string — Match a parsed doc's source function name exactly.
    - `since` string, date-time — Restrict to resources created at or after this timestamp.
  - `range` FSRange — Slice the parse output along page or section dimensions. Used with `op=cat`.
    - `page` integer — Restrict sections to one page (1-indexed).
    - `pageRange` integer[] — Restrict sections to an inclusive page range. Two-element array of `[from, to]` (both 1-indexed).
    - `sectionTypes` string[] — Keep only sections whose `type` matches one of these (e.g. `["table", "list"]`).
  - `select` string[] — Project the parse output to specific dotted paths (e.g. `["sections.label", "sections.page"]`), letting an agent map a doc's structure cheaply before reading content. Used with `op=cat`.
  - `n` integer — First-N count for `op=head`. Defaults to 10.
  - `limit` integer — Maximum results to return. Defaults vary per op (25–50).
  - `cursor` string — Pagination cursor. Pass the last item's ID from a previous response (`nextCursor`) to fetch the next page.

## Response `200`

The request has succeeded.

- FSResponse — Uniform response shape returned for every `op`. `data` is op-specific JSON (a list, an object, or a string), but the wrapper is constant so a client only learns one parse path.
  - `op` 'ls' | 'find' | 'open' | 'cat' | 'grep' | 'xref' | 'stat' | 'head', required — Operations exposed by `POST /v3/fs`. The verbs and their flag names mirror Unix tools so an LLM agent's existing vocabulary maps directly: - `ls` — list parsed documents - `cat` — read one parsed doc (optionally sliced by range / projected by select) - `grep` — substring or regex search across parse outputs - `head` — first N sections of one doc - `stat` — metadata only (page count, section count, parsed at, ...) - `find` — list canonical entities (cross-doc memory) - `open` — entity + mentions - `xref` — entity → sections across docs that mention it Doc-level ops (ls, cat, grep, head, stat) work on every parsed document, regardless of how the parse function was configured. Memory-level ops (find, open, xref) operate on the global entities table which is only populated when the parse function had `linkAcrossDocuments: true`. On environments with no memory-linked docs they return empty data with a hint pointing at the toggle.
  - `data` unknown, required
  - `hasMore` boolean — True when more pages exist for cursor-paginated ops.
  - `nextCursor` string — Cursor to pass as `cursor` in the next request to fetch the next page. Empty when `hasMore=false`.
  - `count` integer — Set for ops that return a count rather than a list (`grep` with `countOnly=true`) or as a sanity check on lists.
  - `hint` string — Optional human-readable note. Surfaced on memory-level ops (`find` / `open` / `xref`) when the corpus has no memory-linked docs, pointing users at the `linkAcrossDocuments` toggle on the parse function.

---

[API](https://skmtc.net/bem-team/apis/bem-api.md) · [All operations](https://skmtc.net/bem-team/apis/bem-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/bem-team/bem-api/versions/b0a6debb3458/schema)
