Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ poetry run ruff check slayer/ tests/

## CLI

- All commands accept `--storage` (directory for YAML, `.db` file for SQLite). Defaults to platform-appropriate path (`~/.local/share/slayer` on Linux, `~/Library/Application Support/slayer` on macOS). Override with `$SLAYER_STORAGE` env var. Legacy `--models-dir` still works.
- All commands accept `--storage` (directory for YAML, `.db` file for SQLite). Defaults to platform-appropriate path (`~/.local/share/slayer` on Linux, `~/Library/Application Support/slayer` on macOS, `%LOCALAPPDATA%\slayer` on Windows). Override with `$SLAYER_STORAGE` env var.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be ~/.local/share/slayer on Mac as well

- `slayer query` supports `--dry-run` (preview SQL) and `--explain` (execution plan, dialect-aware).
- `slayer datasources create-inline` supports `--password-stdin` for secure credential input.
- `slayer datasources test` verifies connectivity.
Expand Down
26 changes: 21 additions & 5 deletions docs/configuration/storage.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
# Storage Backends
# Storage

SLayer uses a storage backend to persist model and datasource configurations.
SLayer uses a storage backend to persist model and datasource configurations, agent memories, and embedding indexes.

## Default Location

When no `--storage` flag or `$SLAYER_STORAGE` env var is set, SLayer uses a platform-appropriate default:
When no `--storage` flag or `$SLAYER_STORAGE` env var is set, SLayer picks a platform-appropriate default:

| Platform | Default path |
|---|---|
| Linux | `~/.local/share/slayer` (or `$XDG_DATA_HOME/slayer`) |
| Linux | `~/.local/share/slayer` (or `$XDG_DATA_HOME/slayer` if set) |
| macOS | `~/Library/Application Support/slayer` |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

| Windows | `%LOCALAPPDATA%\slayer` |

This means `slayer serve` works out of the box with no flags. Override with `--storage` or `$SLAYER_STORAGE`.
This means `slayer serve` works out of the box with no flags.

## Overriding the Storage Path

Pass `--storage` to any CLI command, or set the `$SLAYER_STORAGE` environment variable:

```bash
# YAML directory
slayer serve --storage ./slayer_data

# SQLite database (auto-detected by .db/.sqlite/.sqlite3 extension)
slayer serve --storage slayer.db

# Or via environment variable
export SLAYER_STORAGE=./my_project/slayer_data
slayer serve
```

## Available Backends

Expand Down
2 changes: 1 addition & 1 deletion docs/dbt/dbt_import.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ Arguments:

Options:
--datasource NAME SLayer datasource name for imported models (required)
--storage PATH Storage directory for output (default: ./slayer_data)
--storage PATH Storage directory for output (default: platform path, see Storage docs)
--include-hidden-models Also import regular dbt models (not wrapped by a
semantic_model) as hidden SLayer models via SQL
introspection. Requires the `dbt` extra.
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ claude mcp list

The recommended approach is to drop a datasource YAML file into your storage folder. This keeps credentials out of the agent conversation and lets you use environment variable references.

Create a file at `slayer_data/datasources/mydb.yaml`:
Create a file in the `datasources/` subdirectory of your [storage path](../configuration/storage.md) (e.g. `~/.local/share/slayer/datasources/mydb.yaml`):

```yaml
name: mydb
Expand Down
22 changes: 5 additions & 17 deletions docs/interfaces/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,9 @@ SLayer provides a command-line interface for server management, querying, and mo

## Storage

All commands accept a `--storage` flag to specify where models and datasources are stored:
All commands accept a `--storage` flag to specify where models and datasources are stored. When omitted, SLayer uses a platform-appropriate default (`~/.local/share/slayer` on Linux, `~/Library/Application Support/slayer` on macOS, `%LOCALAPPDATA%\slayer` on Windows). See [Storage](../configuration/storage.md) for full details on backends, resolution, and overrides.

```bash
# YAML files in a directory (default)
slayer serve --storage ./slayer_data

# SQLite database file (auto-detected by .db/.sqlite/.sqlite3 extension)
slayer serve --storage slayer.db
```

If unset, SLayer uses a platform-appropriate path: `~/.local/share/slayer` on Linux, `~/Library/Application Support/slayer` on macOS, `%LOCALAPPDATA%\slayer` on Windows. Override with `$SLAYER_STORAGE`.

Another environment variable, `SLAYER_INGEST_ON_STARTUP`, mirrors the `--ingest-on-startup` flag on `slayer serve` / `slayer mcp` — truthy values (`1`, `true`, `yes`, case-insensitive) enable boot-time idempotent auto-ingestion across every configured datasource. See [Ingesting at Startup](../concepts/ingestion.md#ingesting-at-startup).

The legacy `--models-dir` flag still works but is deprecated in favor of `--storage`.
The `SLAYER_INGEST_ON_STARTUP` environment variable mirrors the `--ingest-on-startup` flag on `slayer serve` / `slayer mcp` — truthy values (`1`, `true`, `yes`, case-insensitive) enable boot-time idempotent auto-ingestion across every configured datasource. See [Ingesting at Startup](../concepts/ingestion.md#ingesting-at-startup).

## Commands

Expand All @@ -36,7 +24,7 @@ slayer serve --storage slayer.db
|------|---------|-------------|
| `--host` | `0.0.0.0` | Bind address |
| `--port` | `5143` | Port number |
| `--storage` | platform-appropriate path | Storage path (directory for YAML, `.db` file for SQLite) |
| `--storage` | [platform default](../configuration/storage.md) | Storage path (directory for YAML, `.db` file for SQLite) |
| `--demo` | off | Spin up the bundled Jaffle Shop DuckDB datasource and ingest its models on startup. Idempotent; requires the `duckdb` extra and `jafgen`. |
| `--ingest-on-startup` | off | Walk every configured datasource and run idempotent auto-ingestion before the port opens. Per-datasource errors are logged to stderr and never abort startup. Also enabled by `SLAYER_INGEST_ON_STARTUP=1`. |

Expand All @@ -56,7 +44,7 @@ For MCP over HTTP (SSE), use `slayer serve` instead — it exposes MCP at `/mcp/

| Flag | Default | Description |
|------|---------|-------------|
| `--storage` | platform-appropriate path | Storage path (directory for YAML, `.db` file for SQLite) |
| `--storage` | [platform default](../configuration/storage.md) | Storage path (directory for YAML, `.db` file for SQLite) |
| `--demo` | off | Spin up the bundled Jaffle Shop DuckDB datasource and ingest its models on startup. Idempotent; requires the `duckdb` extra and `jafgen`. |
| `--ingest-on-startup` | off | Walk every configured datasource and run idempotent auto-ingestion before stdio JSON-RPC starts. Per-datasource errors are logged to stderr and never abort startup. Also enabled by `SLAYER_INGEST_ON_STARTUP=1`. |

Expand Down Expand Up @@ -96,7 +84,7 @@ The positional argument is interpreted as:

| Flag | Default | Description |
|------|---------|-------------|
| `--storage` | platform-appropriate path | Storage path (directory for YAML, `.db` file for SQLite) |
| `--storage` | [platform default](../configuration/storage.md) | Storage path (directory for YAML, `.db` file for SQLite) |
| `--format` | `table` | Output format: `table` or `json` |
| `--dry-run` | | Generate SQL without executing |
| `--explain` | | Run EXPLAIN ANALYZE on the query |
Expand Down
8 changes: 5 additions & 3 deletions docs/interfaces/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ The agent spawns SLayer as a subprocess and communicates via stdin/stdout. You d
**Claude Code setup:**

```bash
claude mcp add slayer -- slayer mcp --ingest-on-startup --storage ./slayer_data
claude mcp add slayer -- slayer mcp --ingest-on-startup
```

`--ingest-on-startup` runs idempotent auto-ingestion across every configured datasource before the stdio channel opens. Drop the flag (or set `SLAYER_INGEST_ON_STARTUP=0`) to defer ingestion to a manual `ingest_datasource_models` call.

Storage defaults to the [platform-appropriate path](../configuration/storage.md). Override with `--storage /path/to/data` if needed.

If `slayer` is installed in a virtualenv (e.g. via Poetry), use the full path to the executable so the agent can find it regardless of working directory:

```bash
Expand All @@ -26,7 +28,7 @@ poetry env info -p
# e.g. /home/user/.venvs/slayer-abc123

# Register with the full path
claude mcp add slayer -- /home/user/.venvs/slayer-abc123/bin/slayer mcp --storage /path/to/slayer_data
claude mcp add slayer -- /home/user/.venvs/slayer-abc123/bin/slayer mcp
```

### SSE (remote)
Expand All @@ -35,7 +37,7 @@ MCP over HTTP via Server-Sent Events. You run `slayer serve` yourself — it exp

```bash
# 1. Start the server
slayer serve --ingest-on-startup --storage ./slayer_data
slayer serve --ingest-on-startup
# REST API at http://localhost:5143/
# MCP SSE at http://localhost:5143/mcp/sse
```
Expand Down
8 changes: 5 additions & 3 deletions docs/interfaces/rest-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ SLayer provides a FastAPI-based REST API on port **5143** by default.
## Start the Server

```bash
slayer serve --storage ./slayer_data
slayer serve --host 0.0.0.0 --port 8080 --storage ./slayer_data
slayer serve
slayer serve --host 0.0.0.0 --port 8080

# Run idempotent auto-ingestion across every configured datasource before
# the port opens. Same as setting SLAYER_INGEST_ON_STARTUP=1.
slayer serve --ingest-on-startup --storage ./slayer_data
slayer serve --ingest-on-startup
```

Storage defaults to the [platform-appropriate path](../configuration/storage.md). Override with `--storage ./slayer_data` or `$SLAYER_STORAGE`.

## Endpoints

### Health Check
Expand Down
20 changes: 4 additions & 16 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,7 @@ SLayer provides a command-line interface for server management, querying, and mo

## Storage

All commands accept a `--storage` flag to specify where models and datasources are stored:

```bash
# YAML files in a directory (default)
slayer serve --storage ./slayer_data

# SQLite database file (auto-detected by .db/.sqlite/.sqlite3 extension)
slayer serve --storage slayer.db
```

The default is `./slayer_data` (YAML). Override with `$SLAYER_STORAGE` or `$SLAYER_MODELS_DIR` env vars.

The legacy `--models-dir` flag still works but is deprecated in favor of `--storage`.
All commands accept a `--storage` flag to specify where models and datasources are stored. When omitted, SLayer uses a platform-appropriate default (`~/.local/share/slayer` on Linux, `~/Library/Application Support/slayer` on macOS, `%LOCALAPPDATA%\slayer` on Windows). See [Storage](../configuration/storage.md) for full details on backends, resolution, and overrides.

## Commands

Expand All @@ -36,7 +24,7 @@ slayer serve --ingest-on-startup # run idempotent ingest over every configur
|------|---------|-------------|
| `--host` | `0.0.0.0` | Bind address |
| `--port` | `5143` | Port number |
| `--storage` | `./slayer_data` | Storage path (directory for YAML, .db file for SQLite) |
| `--storage` | [platform default](../configuration/storage.md) | Storage path (directory for YAML, `.db` file for SQLite) |
| `--demo` | off | Generate and ingest the bundled Jaffle Shop demo before starting (idempotent). |
| `--ingest-on-startup` | off | Walk every configured datasource and run idempotent auto-ingestion before the port opens. Per-datasource errors are logged to stderr and never abort startup. Also enabled by `SLAYER_INGEST_ON_STARTUP=1`. |

Expand All @@ -56,7 +44,7 @@ For MCP over HTTP (SSE), use `slayer serve` instead — it exposes MCP at `/mcp/

| Flag | Default | Description |
|------|---------|-------------|
| `--storage` | `./slayer_data` | Storage path |
| `--storage` | [platform default](../configuration/storage.md) | Storage path (directory for YAML, `.db` file for SQLite) |
| `--demo` | off | Generate and ingest the bundled Jaffle Shop demo before starting (idempotent). |
| `--ingest-on-startup` | off | Walk every configured datasource and run idempotent auto-ingestion before stdio JSON-RPC starts. Per-datasource errors are logged to stderr and never abort startup. Also enabled by `SLAYER_INGEST_ON_STARTUP=1`. |

Expand All @@ -83,7 +71,7 @@ slayer query @query.json --explain

| Flag | Default | Description |
|------|---------|-------------|
| `--storage` | `./slayer_data` | Storage path |
| `--storage` | [platform default](../configuration/storage.md) | Storage path (directory for YAML, `.db` file for SQLite) |
| `--format` | `table` | Output format: `table` or `json` |
| `--dry-run` | | Generate SQL without executing |
| `--explain` | | Run EXPLAIN ANALYZE on the query |
Expand Down
6 changes: 3 additions & 3 deletions docs/reference/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The fastest way to run SLayer is via `uvx` — no install needed. You only need
**Claude Code:**

```bash
claude mcp add slayer -- uvx --from 'motley-slayer[postgres]' slayer mcp --ingest-on-startup --storage ./slayer_data
claude mcp add slayer -- uvx --from 'motley-slayer[postgres]' slayer mcp --ingest-on-startup
```

**JSON config** (Claude Desktop, Cursor, and other MCP-compatible agents):
Expand All @@ -19,7 +19,7 @@ claude mcp add slayer -- uvx --from 'motley-slayer[postgres]' slayer mcp --inges
"mcpServers": {
"slayer": {
"command": "uvx",
"args": ["--from", "motley-slayer[postgres]", "slayer", "mcp", "--ingest-on-startup", "--storage", "./slayer_data"]
"args": ["--from", "motley-slayer[postgres]", "slayer", "mcp", "--ingest-on-startup"]
}
}
}
Expand All @@ -44,7 +44,7 @@ The agent spawns SLayer as a subprocess and communicates via stdin/stdout. You d
MCP over HTTP via Server-Sent Events. You run `slayer serve` yourself — it exposes both the REST API and the MCP SSE endpoint on the same port:

```bash
uvx --from 'motley-slayer[postgres]' slayer serve --ingest-on-startup --storage ./slayer_data
uvx --from 'motley-slayer[postgres]' slayer serve --ingest-on-startup
# REST API at http://localhost:5143/
# MCP SSE at http://localhost:5143/mcp/sse
```
Expand Down
8 changes: 6 additions & 2 deletions slayer/storage/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Abstract storage protocol and factory."""

import os
import sys
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Tuple
Expand Down Expand Up @@ -41,7 +42,7 @@ def default_storage_path() -> str:
2. $SLAYER_MODELS_DIR environment variable (legacy, if set)
3. Platform default:
- Linux: $XDG_DATA_HOME/slayer (defaults to ~/.local/share/slayer)
- macOS: ~/Library/Application Support/slayer
- macOS: ~/Library/Application Support/slayer (ignores $XDG_DATA_HOME)
- Windows: %LOCALAPPDATA%/slayer
"""
env = os.environ.get("SLAYER_STORAGE") or os.environ.get("SLAYER_MODELS_DIR")
Expand All @@ -51,8 +52,11 @@ def default_storage_path() -> str:
if os.name == "nt":
# Windows
base = Path(os.getenv("LOCALAPPDATA", Path.home() / "AppData" / "Local"))
elif sys.platform == "darwin":
# macOS
base = Path.home() / "Library" / "Application Support"
else:
# MacOS, Linux, etc.
# Linux, etc.
base = Path(os.getenv("XDG_DATA_HOME", Path.home() / ".local" / "share"))

return str(base / "slayer")
Expand Down
Loading