Skip to content

File System

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

WebDAV (Phase 1)

OpenViking Server also exposes a minimal WebDAV adapter for resource files:

text
/webdav/resources

Phase 1 intentionally keeps the scope narrow:

  • Resources only. Memories, skills, sessions, and other namespaces are not exposed.
  • Text-first writes. PUT currently accepts UTF-8 text content only.
  • WebDAV subset only. OPTIONS, PROPFIND, GET, HEAD, PUT, DELETE, MKCOL, and MOVE are supported.
  • Semantic sidecars stay internal. Derived files such as .abstract.md, .overview.md, .relations.json, and .path.ovlock are hidden from listings and cannot be accessed directly through WebDAV.

Behavior notes:

  • Creating a new file through WebDAV triggers OpenViking semantic generation for that file path.
  • Replacing an existing file through WebDAV refreshes related semantics and vectors, same as write().
  • User-created dot-directories and dot-files remain visible unless they match one of the reserved internal filenames above.

API Reference

abstract()

Read L0 abstract (~100 tokens summary).

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI (must be a directory)

Python SDK (Embedded / HTTP)

python
abstract = client.abstract("viking://resources/docs/")
print(f"Abstract: {abstract}")
# Output: "Documentation for the project API, covering authentication, endpoints..."

HTTP API

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

CLI

bash
openviking abstract viking://resources/docs/

Response

json
{
  "status": "ok",
  "result": "Documentation for the project API, covering authentication, endpoints...",
  "time": 0.1
}

overview()

Read L1 overview, applies to directories.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI (must be a directory)

Python SDK (Embedded / HTTP)

python
overview = client.overview("viking://resources/docs/")
print(f"Overview:\n{overview}")

HTTP API

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

CLI

bash
openviking overview viking://resources/docs/

Response

json
{
  "status": "ok",
  "result": "## docs/\n\nContains API documentation and guides...",
  "time": 0.1
}

read()

Read L2 full content.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI
offsetintNo0Starting line number (0-indexed)
limitintNo-1Number of lines to read, -1 means read to end

Notes

  • read() accepts file URIs only. Passing an existing directory URI returns INVALID_ARGUMENT (400), not NOT_FOUND.
  • Public URI parameters accept resources, user, agent, and session scopes. Internal scopes such as temp and queue return INVALID_URI.

Python SDK (Embedded / HTTP)

python
content = client.read("viking://resources/docs/api.md")
print(f"Content:\n{content}")

HTTP API

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

CLI

bash
openviking read viking://resources/docs/api.md

Response

json
{
  "status": "ok",
  "result": "# API Documentation\n\nFull content of the file...",
  "time": 0.1
}

write()

Update an existing file, or create a new one when mode="create", and automatically refresh related semantics and vectors.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Existing file URI
contentstrYes-New content to write
modestrNoreplacereplace, append, or create
waitboolNofalseWait for background semantic/vector refresh
timeoutfloatNonullTimeout in seconds when wait=true

Notes

  • replace and append require the file to exist; create targets a new file and returns 409 Conflict when the path already exists. Directories are always rejected.
  • create only accepts text-writable extensions: .md, .txt, .json, .yaml, .yml, .toml, .py, .js, .ts. Parent directories are created automatically.
  • Derived semantic files cannot be written directly: .abstract.md, .overview.md, .relations.json.
  • File content is updated before the API returns. wait only controls whether the call waits for semantic/vector refresh to finish.
  • The public API no longer accepts regenerate_semantics or revectorize; write always refreshes related semantics and vectors.

Python SDK (Embedded / HTTP)

python
result = client.write(
    "viking://resources/docs/api.md",
    "# Updated API\n\nFresh content.",
    mode="replace",
    wait=True,
)
print(result["root_uri"])

HTTP API

POST /api/v1/content/write
bash
curl -X POST "http://localhost:1933/api/v1/content/write" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "uri": "viking://resources/docs/api.md",
    "content": "# Updated API\n\nFresh content.",
    "mode": "replace",
    "wait": true
  }'

CLI

bash
openviking write viking://resources/docs/api.md \
  --content "# Updated API\n\nFresh content." \
  --wait

Response

json
{
  "status": "ok",
  "result": {
    "uri": "viking://resources/docs/api.md",
    "root_uri": "viking://resources/docs",
    "context_type": "resource",
    "mode": "replace",
    "written_bytes": 29,
    "content_updated": true,
    "semantic_status": "complete",
    "vector_status": "complete",
    "queue_status": {
      "Semantic": {
        "processed": 1,
        "error_count": 0,
        "errors": []
      },
      "Embedding": {
        "processed": 2,
        "error_count": 0,
        "errors": []
      }
    }
  }
}

ls()

List directory contents.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI
simpleboolNoFalseReturn only relative paths
recursiveboolNoFalseList all subdirectories recursively
outputstrNoagentOutput format: agent or original
abs_limitintNo256Abstract length limit for agent output
show_all_hiddenboolNoFalseInclude hidden files like -a
node_limitintNo1000Maximum number of nodes to return
limitintNoNoneAlias for node_limit

Entry Structure

python
{
    "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 SDK (Embedded / HTTP)

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

HTTP API

GET /api/v1/fs/ls?uri={uri}&simple={bool}&recursive={bool}
bash
# 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

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

Response

json
{
  "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
outputstrNoagentOutput format: agent or original
abs_limitintNo256Abstract length limit for agent output
show_all_hiddenboolNoFalseInclude hidden files like -a
node_limitintNo1000Maximum number of nodes to return
limitintNoNoneAlias for node_limit
level_limitintNo3Maximum directory depth to traverse

Python SDK (Embedded / HTTP)

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

HTTP API

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

CLI

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

Response

json
{
  "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.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI

Python SDK (Embedded / HTTP)

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

HTTP API

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

CLI

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

Response

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

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 SDK (Embedded / HTTP)

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

HTTP API

POST /api/v1/fs/mkdir
bash
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

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

Response

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

rm()

Remove file or directory.

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 SDK (Embedded / HTTP)

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

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

HTTP API

DELETE /api/v1/fs?uri={uri}&recursive={bool}
bash
# 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

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

Response

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

mv()

Move file or directory.

Parameters

ParameterTypeRequiredDefaultDescription
from_uristrYes-Source Viking URI
to_uristrYes-Destination Viking URI

Python SDK (Embedded / HTTP)

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

HTTP API

POST /api/v1/fs/mv
bash
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

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

Response

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

grep()

Search content by pattern.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI to search in
patternstrYes-Search pattern (regex)
case_insensitiveboolNoFalseIgnore case
exclude_uristrNoNoneURI prefix to exclude from search
node_limitintNoNoneMaximum number of nodes to search
level_limitintNo5Maximum directory depth to traverse

Python SDK (Embedded / HTTP)

python
results = client.grep(
    "viking://resources/",
    "authentication",
    case_insensitive=True
)

print(f"Found {results['count']} matches")
for match in results['matches']:
    print(f"  {match['uri']}:{match['line']}")
    print(f"    {match['content']}")

HTTP API

POST /api/v1/search/grep
bash
curl -X POST http://localhost:1933/api/v1/search/grep \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "uri": "viking://resources/",
    "pattern": "authentication",
    "case_insensitive": true
  }'

CLI

bash
openviking grep viking://resources/ "authentication" [--ignore-case]

Response

json
{
  "status": "ok",
  "result": {
    "matches": [
      {
        "uri": "viking://resources/docs/auth.md",
        "line": 15,
        "content": "User authentication is handled by..."
      }
    ],
    "count": 1
  },
  "time": 0.1
}

glob()

Match files by pattern.

Parameters

ParameterTypeRequiredDefaultDescription
patternstrYes-Glob pattern (e.g., **/*.md)
uristrNo"viking://"Starting URI
node_limitintNoNoneMaximum number of matches to return

Python SDK (Embedded / HTTP)

python
# Find all markdown files
results = client.glob("**/*.md", "viking://resources/")
print(f"Found {results['count']} markdown files:")
for uri in results['matches']:
    print(f"  {uri}")

# Find all Python files
results = client.glob("**/*.py", "viking://resources/")
print(f"Found {results['count']} Python files")

HTTP API

POST /api/v1/search/glob
bash
curl -X POST http://localhost:1933/api/v1/search/glob \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "pattern": "**/*.md",
    "uri": "viking://resources/"
  }'

CLI

bash
openviking glob "**/*.md" [--uri viking://resources/]

Response

json
{
  "status": "ok",
  "result": {
    "matches": [
      "viking://resources/docs/api.md",
      "viking://resources/docs/guide.md"
    ],
    "count": 2
  },
  "time": 0.1
}

Create relations between resources.

Parameters

ParameterTypeRequiredDefaultDescription
from_uristrYes-Source URI
to_urisstr or List[str]Yes-Target URI(s)
reasonstrNo""Reason for the link

Python SDK (Embedded / HTTP)

python
# Single link
client.link(
    "viking://resources/docs/auth/",
    "viking://resources/docs/security/",
    reason="Security best practices for authentication"
)

# Multiple links
client.link(
    "viking://resources/docs/api/",
    [
        "viking://resources/docs/auth/",
        "viking://resources/docs/errors/"
    ],
    reason="Related documentation"
)

HTTP API

POST /api/v1/relations/link
bash
# Single link
curl -X POST http://localhost:1933/api/v1/relations/link \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "from_uri": "viking://resources/docs/auth/",
    "to_uris": "viking://resources/docs/security/",
    "reason": "Security best practices for authentication"
  }'

# Multiple links
curl -X POST http://localhost:1933/api/v1/relations/link \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "from_uri": "viking://resources/docs/api/",
    "to_uris": ["viking://resources/docs/auth/", "viking://resources/docs/errors/"],
    "reason": "Related documentation"
  }'

CLI

bash
openviking link viking://resources/docs/auth/ viking://resources/docs/security/ --reason "Security best practices"

Response

json
{
  "status": "ok",
  "result": {
    "from": "viking://resources/docs/auth/",
    "to": "viking://resources/docs/security/"
  },
  "time": 0.1
}

relations()

Get relations for a resource.

Parameters

ParameterTypeRequiredDefaultDescription
uristrYes-Viking URI

Python SDK (Embedded / HTTP)

python
relations = client.relations("viking://resources/docs/auth/")
for rel in relations:
    print(f"Related: {rel['uri']}")
    print(f"  Reason: {rel['reason']}")

HTTP API

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

CLI

bash
openviking relations viking://resources/docs/auth/

Response

json
{
  "status": "ok",
  "result": [
    {"uri": "viking://resources/docs/security/", "reason": "Security best practices"},
    {"uri": "viking://resources/docs/errors/", "reason": "Error handling"}
  ],
  "time": 0.1
}

Remove a relation.

Parameters

ParameterTypeRequiredDefaultDescription
from_uristrYes-Source URI
to_uristrYes-Target URI to unlink

Python SDK (Embedded / HTTP)

python
client.unlink(
    "viking://resources/docs/auth/",
    "viking://resources/docs/security/"
)

HTTP API

DELETE /api/v1/relations/link
bash
curl -X DELETE http://localhost:1933/api/v1/relations/link \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "from_uri": "viking://resources/docs/auth/",
    "to_uri": "viking://resources/docs/security/"
  }'

CLI

bash
openviking unlink viking://resources/docs/auth/ viking://resources/docs/security/

Response

json
{
  "status": "ok",
  "result": {
    "from": "viking://resources/docs/auth/",
    "to": "viking://resources/docs/security/"
  },
  "time": 0.1
}

Released under the Apache-2.0 License.