File System

August 10, 2026 ยท View on GitHub

OpenViking provides Unix-like file system operations for managing context.

API Reference

ls()

List directory contents.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI
simpleboolNoFalseReturn only relative paths
recursiveboolNoFalseList all subdirectories recursively
outputstrNoHTTP: agent; SDKs: originalOutput format: agent or original
abs_limitintNo256Abstract length limit for agent output
show_all_hiddenboolNoFalseInclude hidden files like -a
node_limitintNo1000Maximum number of results
sort_bystrNoNoneSort directories and files within their groups by name or mtime before applying node_limit; directories remain first
sort_orderstrNoascSort direction: asc or desc

Entry Structure

{
    "name": "docs",           # File/directory name
    "size": 4096,             # Size in bytes
    "mode": 16877,            # File mode
    "modTime": "2024-01-01T00:00:00Z",  # ISO timestamp
    "isDir": True,            # True if directory
    "uri": "viking://resources/docs/",  # Viking URI
    "meta": {}                # Optional metadata
}

Python HTTP SDK

entries = client.ls(
    "viking://resources/",
    node_limit=200,
    sort_by="mtime",
    sort_order="desc",
)
for entry in entries:
    type_str = "dir" if entry['isDir'] else "file"
    print(f"{entry['name']} - {type_str}")

TypeScript SDK

const entries = await client.list("viking://resources/docs/", { simple: true });
console.log(entries);

Go SDK

entries, err := client.List(ctx, "viking://resources/", nil)
if err != nil {
    return err
}
for _, entry := range entries {
    fmt.Println(entry)
}

HTTP API

GET /api/v1/fs/ls?uri={uri}&simple={bool}&recursive={bool}
# Basic listing
curl -X GET "http://localhost:1933/api/v1/fs/ls?uri=viking://resources/" \
  -H "X-API-Key: your-key"

# Simple path list
curl -X GET "http://localhost:1933/api/v1/fs/ls?uri=viking://resources/&simple=true" \
  -H "X-API-Key: your-key"

# Recursive listing
curl -X GET "http://localhost:1933/api/v1/fs/ls?uri=viking://resources/&recursive=true" \
  -H "X-API-Key: your-key"

CLI

openviking ls viking://resources/ [--simple] [--recursive]

Response

{
  "status": "ok",
  "result": [
    {
      "name": "docs",
      "size": 4096,
      "mode": 16877,
      "modTime": "2024-01-01T00:00:00Z",
      "isDir": true,
      "uri": "viking://resources/docs/"
    }
  ],
  "time": 0.1
}

tree()

Get directory tree structure.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI
outputstrNoHTTP: agent; SDKs: originalOutput format: agent or original
abs_limitintNoHTTP: 256; SDKs: 128Abstract length limit for agent output
show_all_hiddenboolNoFalseInclude hidden files like -a
node_limitintNo1000Maximum number of results
level_limitintNo3Maximum directory depth to traverse

Python HTTP SDK

entries = client.tree("viking://resources/")
for entry in entries:
    type_str = "dir" if entry['isDir'] else "file"
    print(f"{entry['rel_path']} - {type_str}")

TypeScript SDK

const tree = await client.tree("viking://resources/docs/", { nodeLimit: 100 });
console.log(tree);

Go SDK

entries, err := client.Tree(ctx, "viking://resources/", nil)
if err != nil {
    return err
}
for _, entry := range entries {
    fmt.Println(entry["rel_path"], entry["isDir"])
}

HTTP API

GET /api/v1/fs/tree?uri={uri}
curl -X GET "http://localhost:1933/api/v1/fs/tree?uri=viking://resources/" \
  -H "X-API-Key: your-key"

CLI

openviking tree viking://resources/my-project/

Response

{
  "status": "ok",
  "result": [
    {
      "name": "docs",
      "size": 4096,
      "isDir": true,
      "rel_path": "docs/",
      "uri": "viking://resources/docs/"
    },
    {
      "name": "api.md",
      "size": 1024,
      "isDir": false,
      "rel_path": "docs/api.md",
      "uri": "viking://resources/docs/api.md"
    }
  ],
  "time": 0.1
}

stat()

Get file or directory status information. For directories, returns the count of items under the directory.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI

Python HTTP SDK

info = client.stat("viking://resources/docs/api.md")
print(f"Size: {info['size']}")
print(f"Is directory: {info['isDir']}")

# For directories, returns item count
dir_info = client.stat("viking://resources/docs")
if dir_info.get('isDir'):
    print(f"Item count: {dir_info.get('count')}")

TypeScript SDK

const metadata = await client.stat("viking://resources/docs/api.md");
console.log(metadata);

Go SDK

info, err := client.Stat(ctx, "viking://resources/docs/api.md")
if err != nil {
    return err
}
fmt.Println(info["size"], info["isDir"])

HTTP API

GET /api/v1/fs/stat?uri={uri}
curl -X GET "http://localhost:1933/api/v1/fs/stat?uri=viking://resources/docs/api.md" \
  -H "X-API-Key: your-key"

CLI

openviking stat viking://resources/my-project/docs/api.md
openviking stat viking://resources/my-project/docs

Response (File)

{
  "status": "ok",
  "result": {
    "name": "api.md",
    "size": 1024,
    "mode": 33188,
    "modTime": "2024-01-01T00:00:00Z",
    "isDir": false,
    "isLocked": false,
    "uri": "viking://resources/docs/api.md"
  },
  "time": 0.1
}

Response (Directory)

{
  "status": "ok",
  "result": {
    "name": "docs",
    "size": 4096,
    "mode": 16877,
    "modTime": "2024-01-01T00:00:00Z",
    "isDir": true,
    "isLocked": false,
    "uri": "viking://resources/docs",
    "count": 42
  },
  "time": 0.1
}

The isLocked field reports whether the path is currently held by a path lock: the path itself has a valid lock (including an exact-path lock for the target), or any ancestor directory holds a TreeLock. Returns false when the LockManager is unavailable or the lookup fails, so callers can avoid attempting a write only to observe ResourceBusyError.

The count field (directories only) contains the estimated number of items (files and subdirectories) under this directory (from vector index).


attrs()

Get logical extended attributes for a file or directory.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI

Python SDK (HTTP)

attrs = client.attrs("viking://resources/docs/api.md")
print(attrs["attrs"]["tags"])

TypeScript SDK

const attributes = await client.attrs("viking://resources/docs/api.md");
console.log(attributes);

Go SDK

attrs, err := client.Attrs(ctx, "viking://resources/docs/api.md")
if err != nil {
    return err
}
metadata := attrs["attrs"].(map[string]any)
fmt.Println(metadata["tags"])

HTTP API

GET /api/v1/fs/attrs?uri={uri}
POST /api/v1/fs/attrs/set_tags
curl -X GET "http://localhost:1933/api/v1/fs/attrs?uri=viking://resources/docs/api.md" \
  -H "X-API-Key: your-key"

curl -X POST "http://localhost:1933/api/v1/fs/attrs/set_tags" \
  -H "X-API-Key: your-key" \
  -H "Content-Type: application/json" \
  -d '{"uri":"viking://resources/docs","tags":["team=search"],"mode":"append","recursive":true}'

CLI

openviking attrs get viking://resources/docs/api.md
openviking attrs get viking://resources/docs/api.md tags
openviking attrs get viking://user/alice/memories/experiences/foo.md memory.resource_refs
openviking attrs set-tags viking://resources/docs/api.md --tags team=search,env=prod
openviking attrs set-tags viking://resources/docs --tags team=search --mode append --recursive

Directory targets update the directory semantic records; recursive=true also updates existing descendant files and directory semantic records.

Response (Resource)

{
  "status": "ok",
  "result": {
    "uri": "viking://resources/docs/api.md",
    "context_type": "resource",
    "attrs": {
      "tags": ["team=search", "env=prod"]
    }
  }
}

Response (Memory)

{
  "status": "ok",
  "result": {
    "uri": "viking://user/alice/memories/experiences/foo.md",
    "context_type": "memory",
    "attrs": {
      "memory": {
        "memory_type": "experiences",
        "name": "foo",
        "tags": ["ui"],
        "resource_refs": ["viking://resources/docs/api.md"]
      },
      "tags": ["team=search"]
    }
  }
}

attrs.memory is parsed from MEMORY_FIELDS metadata with content removed. attrs.tags is the explicit retrieval tag list used by attrs set-tags and search filters.


mkdir()

Create a directory.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI for the new directory
descriptionstrNonullInitial directory description. When provided, it is written to .abstract.md and queued for L0 vectorization.

Python HTTP SDK

client.mkdir("viking://resources/new-project/")
client.mkdir("viking://resources/new-project/", description="API docs directory")

TypeScript SDK

await client.mkdir("viking://resources/docs/guides/", "Project guides");

Go SDK

if err := client.Mkdir(ctx, "viking://resources/new-project/", "API docs directory"); err != nil {
    return err
}

HTTP API

POST /api/v1/fs/mkdir
curl -X POST http://localhost:1933/api/v1/fs/mkdir \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "uri": "viking://resources/new-project/",
    "description": "API docs directory"
  }'

CLI

openviking mkdir viking://resources/new-project/
openviking mkdir viking://resources/new-project/ --description "API docs directory"

Response

{
  "status": "ok",
  "result": {
    "uri": "viking://resources/new-project/"
  },
  "time": 0.1
}

rm()

Remove file or directory. When removing directories recursively, returns the estimated number of items deleted.

rm is idempotent: removing a valid URI that does not exist still succeeds. Invalid URI formats, unsupported schemes, and non-public scopes return INVALID_URI.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI to remove
recursiveboolNoFalseRemove directory recursively

Python HTTP SDK

# Remove single file
client.rm("viking://resources/docs/old.md")

# Remove directory recursively
client.rm("viking://resources/old-project/", recursive=True)

TypeScript SDK

await client.remove("viking://resources/docs/old.md", { wait: true });

Go SDK

err := client.Remove(ctx, "viking://resources/old-project/", &openviking.RemoveOptions{
    Recursive: true,
})
if err != nil {
    return err
}

HTTP API

DELETE /api/v1/fs?uri={uri}&recursive={bool}
# Remove single file
curl -X DELETE "http://localhost:1933/api/v1/fs?uri=viking://resources/docs/old.md" \
  -H "X-API-Key: your-key"

# Remove directory recursively
curl -X DELETE "http://localhost:1933/api/v1/fs?uri=viking://resources/old-project/&recursive=true" \
  -H "X-API-Key: your-key"

CLI

openviking rm viking://resources/old.md [--recursive]

Response (Single file)

{
  "status": "ok",
  "result": {
    "uri": "viking://resources/docs/old.md"
  },
  "time": 0.1
}

Response (Recursive delete)

{
  "status": "ok",
  "result": {
    "uri": "viking://resources/old-project/",
    "estimated_deleted_count": 42
  },
  "time": 0.1
}

The estimated_deleted_count field (for recursive deletes) contains the estimated number of items (files and directories) deleted (from vector index). The CLI will display this information in output.

When deleting viking://resources/..., the response may include memory_cleanup, indicating that user memories referencing that resource URI were cleaned up before deletion.


mv()

Move file or directory.

Parameters

ParameterTypeRequiredDefaultDescription
from_uristrYes-Source Viking URI
to_uristrYes-Destination Viking URI

Python HTTP SDK

client.mv(
    "viking://resources/old-name/",
    "viking://resources/new-name/"
)

TypeScript SDK

await client.move(
  "viking://resources/docs/old.md",
  "viking://resources/docs/new.md",
);

Go SDK

if err := client.Move(ctx, "viking://resources/old-name/", "viking://resources/new-name/"); err != nil {
    return err
}

HTTP API

POST /api/v1/fs/mv
curl -X POST http://localhost:1933/api/v1/fs/mv \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "from_uri": "viking://resources/old-name/",
    "to_uri": "viking://resources/new-name/"
  }'

CLI

openviking mv viking://resources/old-name/ viking://resources/new-name/

Response

{
  "status": "ok",
  "result": {
    "from": "viking://resources/old-name/",
    "to": "viking://resources/new-name/"
  },
  "time": 0.1
}