wlens 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wlens-0.1.0/.github/workflows/ci.yml +34 -0
- wlens-0.1.0/.github/workflows/release.yml +78 -0
- wlens-0.1.0/.gitignore +24 -0
- wlens-0.1.0/.python-version +1 -0
- wlens-0.1.0/LICENSE +21 -0
- wlens-0.1.0/PKG-INFO +305 -0
- wlens-0.1.0/README.md +249 -0
- wlens-0.1.0/RELEASING.md +44 -0
- wlens-0.1.0/docs/mcp.md +217 -0
- wlens-0.1.0/docs/quickstart.md +181 -0
- wlens-0.1.0/docs/table-catalogs.md +315 -0
- wlens-0.1.0/docs/wlens-yml-reference.md +157 -0
- wlens-0.1.0/examples/events.py +115 -0
- wlens-0.1.0/examples/plans.py +112 -0
- wlens-0.1.0/pyproject.toml +65 -0
- wlens-0.1.0/src/wlens/__init__.py +3 -0
- wlens-0.1.0/src/wlens/adapters/__init__.py +5 -0
- wlens-0.1.0/src/wlens/adapters/base.py +49 -0
- wlens-0.1.0/src/wlens/adapters/dbt.py +262 -0
- wlens-0.1.0/src/wlens/cli.py +549 -0
- wlens-0.1.0/src/wlens/config.py +195 -0
- wlens-0.1.0/src/wlens/entities/__init__.py +5 -0
- wlens-0.1.0/src/wlens/entities/loader.py +179 -0
- wlens-0.1.0/src/wlens/executor/__init__.py +33 -0
- wlens-0.1.0/src/wlens/executor/base.py +219 -0
- wlens-0.1.0/src/wlens/executor/duckdb.py +50 -0
- wlens-0.1.0/src/wlens/executor/postgres.py +29 -0
- wlens-0.1.0/src/wlens/executor/redshift.py +30 -0
- wlens-0.1.0/src/wlens/mcp/__init__.py +1 -0
- wlens-0.1.0/src/wlens/mcp/app.py +173 -0
- wlens-0.1.0/src/wlens/mcp/auth.py +106 -0
- wlens-0.1.0/src/wlens/mcp/logs.py +49 -0
- wlens-0.1.0/src/wlens/mcp/proxy.py +78 -0
- wlens-0.1.0/src/wlens/mcp/server.py +375 -0
- wlens-0.1.0/src/wlens/mcp/share.py +520 -0
- wlens-0.1.0/src/wlens/render/__init__.py +1 -0
- wlens-0.1.0/src/wlens/render/markdown.py +245 -0
- wlens-0.1.0/src/wlens/render/pii.py +169 -0
- wlens-0.1.0/src/wlens/render/preserve.py +23 -0
- wlens-0.1.0/src/wlens/templates/SKILL.md +156 -0
- wlens-0.1.0/src/wlens/templates/__init__.py +1 -0
- wlens-0.1.0/src/wlens/templates/wlens.yml +17 -0
- wlens-0.1.0/tests/__init__.py +0 -0
- wlens-0.1.0/tests/conftest.py +25 -0
- wlens-0.1.0/tests/fixtures/events.tiny.yml +10 -0
- wlens-0.1.0/tests/fixtures/manifest.tiny.json +146 -0
- wlens-0.1.0/tests/test_adapters_dbt.py +99 -0
- wlens-0.1.0/tests/test_cli.py +206 -0
- wlens-0.1.0/tests/test_cli_clean.py +170 -0
- wlens-0.1.0/tests/test_config.py +59 -0
- wlens-0.1.0/tests/test_executor_duckdb.py +105 -0
- wlens-0.1.0/tests/test_executor_readonly.py +58 -0
- wlens-0.1.0/tests/test_mcp_auth.py +146 -0
- wlens-0.1.0/tests/test_mcp_refresh.py +73 -0
- wlens-0.1.0/tests/test_mcp_server.py +348 -0
- wlens-0.1.0/tests/test_mcp_share.py +253 -0
- wlens-0.1.0/tests/test_render_markdown.py +285 -0
- wlens-0.1.0/tests/test_render_pii.py +97 -0
- wlens-0.1.0/uv.lock +1198 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Install uv
|
|
25
|
+
uses: astral-sh/setup-uv@v4
|
|
26
|
+
with:
|
|
27
|
+
enable-cache: true
|
|
28
|
+
cache-dependency-glob: uv.lock
|
|
29
|
+
|
|
30
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
31
|
+
run: uv python install ${{ matrix.python-version }}
|
|
32
|
+
|
|
33
|
+
- name: Run tests
|
|
34
|
+
run: uv run --python ${{ matrix.python-version }} --extra dev pytest -v
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v4
|
|
21
|
+
with:
|
|
22
|
+
enable-cache: true
|
|
23
|
+
cache-dependency-glob: uv.lock
|
|
24
|
+
|
|
25
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
26
|
+
run: uv python install ${{ matrix.python-version }}
|
|
27
|
+
|
|
28
|
+
- name: Run tests
|
|
29
|
+
run: uv run --python ${{ matrix.python-version }} --extra dev pytest -v
|
|
30
|
+
|
|
31
|
+
build:
|
|
32
|
+
needs: [test]
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
|
|
37
|
+
- name: Install uv
|
|
38
|
+
uses: astral-sh/setup-uv@v4
|
|
39
|
+
with:
|
|
40
|
+
enable-cache: true
|
|
41
|
+
cache-dependency-glob: uv.lock
|
|
42
|
+
|
|
43
|
+
- name: Verify tag matches package version
|
|
44
|
+
run: |
|
|
45
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
46
|
+
pkg_version=$(python3 -c "import tomllib, pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])")
|
|
47
|
+
if [ "$tag" != "$pkg_version" ]; then
|
|
48
|
+
echo "::error::Tag '$GITHUB_REF_NAME' does not match pyproject.toml version '$pkg_version'"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
- name: Build distributions
|
|
53
|
+
run: uv build
|
|
54
|
+
|
|
55
|
+
- name: Upload dist artifacts
|
|
56
|
+
uses: actions/upload-artifact@v4
|
|
57
|
+
with:
|
|
58
|
+
name: dist
|
|
59
|
+
path: dist/
|
|
60
|
+
|
|
61
|
+
publish:
|
|
62
|
+
needs: [build]
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
environment:
|
|
65
|
+
name: pypi
|
|
66
|
+
url: https://pypi.org/p/wlens
|
|
67
|
+
permissions:
|
|
68
|
+
id-token: write
|
|
69
|
+
|
|
70
|
+
steps:
|
|
71
|
+
- name: Download dist artifacts
|
|
72
|
+
uses: actions/download-artifact@v4
|
|
73
|
+
with:
|
|
74
|
+
name: dist
|
|
75
|
+
path: dist/
|
|
76
|
+
|
|
77
|
+
- name: Publish to PyPI
|
|
78
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
wlens-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
|
|
5
|
+
*.egg-info/
|
|
6
|
+
.eggs/
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
.venv/
|
|
10
|
+
venv/
|
|
11
|
+
env/
|
|
12
|
+
.python-version.local
|
|
13
|
+
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.coverage
|
|
18
|
+
htmlcov/
|
|
19
|
+
|
|
20
|
+
.DS_Store
|
|
21
|
+
.idea/
|
|
22
|
+
.vscode/
|
|
23
|
+
|
|
24
|
+
.wlens-cache/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
wlens-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Whimsical
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
wlens-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wlens
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Warehouse lens for AI agents — per-table markdown docs + read-only SQL adaptor, zero-runtime schema exploration for Claude Code, Cursor, Continue.
|
|
5
|
+
Project-URL: Homepage, https://github.com/WhimsicalCode/wlens
|
|
6
|
+
Project-URL: Repository, https://github.com/WhimsicalCode/wlens
|
|
7
|
+
Project-URL: Issues, https://github.com/WhimsicalCode/wlens/issues
|
|
8
|
+
Author: Whimsical
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 Whimsical
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: agent,ai,claude-code,cursor,dbt,llm,postgres,redshift,schema,warehouse
|
|
32
|
+
Classifier: Development Status :: 3 - Alpha
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Classifier: Topic :: Database
|
|
40
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
41
|
+
Requires-Python: >=3.11
|
|
42
|
+
Requires-Dist: anyio>=4.5
|
|
43
|
+
Requires-Dist: duckdb>=1.0
|
|
44
|
+
Requires-Dist: mcp>=1.27.0
|
|
45
|
+
Requires-Dist: psycopg2-binary>=2.9
|
|
46
|
+
Requires-Dist: pyngrok>=8.0.0
|
|
47
|
+
Requires-Dist: pyyaml>=6.0
|
|
48
|
+
Requires-Dist: ruamel-yaml>=0.18
|
|
49
|
+
Requires-Dist: starlette>=0.27
|
|
50
|
+
Requires-Dist: uvicorn[standard]>=0.46.0
|
|
51
|
+
Provides-Extra: dev
|
|
52
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
53
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
54
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
55
|
+
Description-Content-Type: text/markdown
|
|
56
|
+
|
|
57
|
+
# wlens
|
|
58
|
+
|
|
59
|
+
> Warehouse lens for AI agents.
|
|
60
|
+
|
|
61
|
+
`wlens` turns your dbt project into per-table markdown docs that any AI agent
|
|
62
|
+
can read, and ships a read-only SQL CLI they can run against your warehouse.
|
|
63
|
+
Works locally via a skill + shell command, or remotely via an MCP server.
|
|
64
|
+
|
|
65
|
+
Works with **Claude Code**, **Cursor**, **Continue**, **Codex**, **Claude Desktop**,
|
|
66
|
+
**Pi** and any MCP-speaking client.
|
|
67
|
+
|
|
68
|
+
## Why
|
|
69
|
+
|
|
70
|
+
Most "semantic layers for AI" make you maintain a parallel schema spec (YAML
|
|
71
|
+
dimensions/measures) and ship a runtime that exposes a fixed menu of queries
|
|
72
|
+
to the LLM. That fights the way modern agents work.
|
|
73
|
+
|
|
74
|
+
wlens goes the other direction. It **exposes the schema as markdown** —
|
|
75
|
+
descriptions, column types, `relationships()` / `accepted_values()` tests,
|
|
76
|
+
parent models, sample rows, compiled SQL — one file per entity. The LLM
|
|
77
|
+
reads like it would any other codebase; when it needs data, it runs a
|
|
78
|
+
read-only SELECT.
|
|
79
|
+
|
|
80
|
+
- **Zero runtime to explore.** Markdown is committed to the repo. No
|
|
81
|
+
warehouse credentials needed until the agent actually runs a query.
|
|
82
|
+
- **Zero parallel definitions.** Reads directly from dbt artifacts.
|
|
83
|
+
- **LLM-optimized format.** Per-column H3 headers for greppability, enum
|
|
84
|
+
values listed inline (via `accepted_values` tests), foreign keys
|
|
85
|
+
surfaced (via `relationships` tests), column-first sample rows,
|
|
86
|
+
one-sentence index summaries.
|
|
87
|
+
- **Human-editable.** The markdown is the data. Team-authored notes
|
|
88
|
+
preserved across regeneration under a marker.
|
|
89
|
+
- **Two deployment modes.** Solo (filesystem + CLI) or team (MCP server
|
|
90
|
+
with bearer auth).
|
|
91
|
+
|
|
92
|
+
## Extensibility
|
|
93
|
+
|
|
94
|
+
Beyond dbt models and sources, wlens lets you describe **table
|
|
95
|
+
catalogs** — per-table catalogs of named row-instances like analytics
|
|
96
|
+
events, feature flags, customer attributes, subscription plans. The
|
|
97
|
+
library teaches no domains: it ships only the base `TableCatalog`
|
|
98
|
+
class plus a plugin loader. New kinds live in *your* repo, and the
|
|
99
|
+
worked examples in [`examples/`](examples/) are sized to be cloned
|
|
100
|
+
and adapted by an LLM agent (Claude Code, Cursor, Codex).
|
|
101
|
+
|
|
102
|
+
See [`docs/table-catalogs.md`](docs/table-catalogs.md).
|
|
103
|
+
|
|
104
|
+
## Quickstart
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# 1. Install
|
|
108
|
+
uv tool install wlens # or: pip install wlens
|
|
109
|
+
|
|
110
|
+
# 2. Initialise at the root of a dbt project
|
|
111
|
+
cd ~/your-dbt-project
|
|
112
|
+
wlens init
|
|
113
|
+
|
|
114
|
+
# 3. Compile the dbt project (needs a profile configured)
|
|
115
|
+
dbt compile
|
|
116
|
+
|
|
117
|
+
# 4. Generate the per-table markdown
|
|
118
|
+
wlens generate
|
|
119
|
+
|
|
120
|
+
# 5. Your AI agent can now explore wlens/schema/ and run queries
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`wlens init` auto-detects `dbt_project.yml` (in cwd, then common subdirs
|
|
124
|
+
like `transform/`, `dbt/`) and any `*.duckdb` file, and wires the config
|
|
125
|
+
accordingly. For Redshift / Postgres you edit a few env var names.
|
|
126
|
+
|
|
127
|
+
After init, your project looks like:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
your-repo/
|
|
131
|
+
wlens.yml # config (root, like pyproject.toml)
|
|
132
|
+
wlens/
|
|
133
|
+
.gitignore # auto: ignores cache/ and share/
|
|
134
|
+
schema/ # generated per-table markdown (commit this)
|
|
135
|
+
_index.md
|
|
136
|
+
<schema>.<table>.md
|
|
137
|
+
cache/ # query cache (gitignored)
|
|
138
|
+
share/ # ngrok config files (gitignored)
|
|
139
|
+
.claude/
|
|
140
|
+
skills/
|
|
141
|
+
wlens/
|
|
142
|
+
SKILL.md # Claude Code skill (convention location)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## The three-move pattern
|
|
146
|
+
|
|
147
|
+
Every warehouse question follows the same shape, regardless of client:
|
|
148
|
+
|
|
149
|
+
1. **Discover** — find candidate tables.
|
|
150
|
+
2. **Read** — open one table's full docs.
|
|
151
|
+
3. **Query** — execute a read-only SELECT.
|
|
152
|
+
|
|
153
|
+
### In filesystem clients (Claude Code, Cursor, Continue, Codex)
|
|
154
|
+
|
|
155
|
+
The LLM uses its built-in `Grep` + `Read` against `wlens/schema/*.md`,
|
|
156
|
+
then shells out to `wlens query "SELECT …"`.
|
|
157
|
+
|
|
158
|
+
### In MCP clients (Claude Desktop, or any hosted MCP client)
|
|
159
|
+
|
|
160
|
+
The LLM calls four **tools** exposed by the wlens MCP server:
|
|
161
|
+
|
|
162
|
+
- `search_models(keyword)` — keyword-grep the docs, returns matches with snippets.
|
|
163
|
+
- `list_models()` — full catalog when no keyword fits.
|
|
164
|
+
- `read_model(name)` — full markdown for one entity.
|
|
165
|
+
- `execute_sql(query)` — run the SELECT.
|
|
166
|
+
|
|
167
|
+
Same pattern, different primitives.
|
|
168
|
+
|
|
169
|
+
## Architecture
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
dbt artifacts → wlens generate → wlens/schema/*.md ─┬─► filesystem agent
|
|
173
|
+
▲ │ (grep + read + wlens query)
|
|
174
|
+
build-time │
|
|
175
|
+
(creds once) └─► MCP server (wlens mcp)
|
|
176
|
+
→ remote agents
|
|
177
|
+
(Claude Desktop, etc.)
|
|
178
|
+
→ search_models / read_model
|
|
179
|
+
/ execute_sql tools
|
|
180
|
+
→ warehouse (read-only, on demand)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## `wlens query` — the CLI
|
|
184
|
+
|
|
185
|
+
A Bash-invocable SQL runner with a **hard read-only guard**. Parses your
|
|
186
|
+
SQL and rejects anything that isn't a single `SELECT` / `WITH … SELECT`.
|
|
187
|
+
Multi-statement queries are also rejected. Results come back as a
|
|
188
|
+
markdown table, cached under `wlens/cache/sql/` with a daily TTL
|
|
189
|
+
(`CURRENT_DATE`-relative queries refresh each day).
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
wlens query "SELECT count(*) FROM main_marts.fct_invoice"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Multi-line via heredoc:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
wlens query <<'SQL'
|
|
199
|
+
select date_trunc('month', invoice_date) as month, sum(total) as revenue
|
|
200
|
+
from main_marts.fct_invoice
|
|
201
|
+
group by 1
|
|
202
|
+
order by 1
|
|
203
|
+
SQL
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## CLI reference
|
|
207
|
+
|
|
208
|
+
| Command | Purpose |
|
|
209
|
+
|---|---|
|
|
210
|
+
| `wlens init` | Write `wlens.yml` + `.claude/skills/wlens/SKILL.md` + `wlens/.gitignore`. Auto-detects dbt project and `.duckdb` files. |
|
|
211
|
+
| `wlens generate` | Read dbt's `target/manifest.json`, write per-table markdown into `wlens/schema/`. |
|
|
212
|
+
| `wlens query "SELECT ..."` | Run a read-only query. |
|
|
213
|
+
| `wlens tag-pii` | Scan dbt yml, add `meta: pii: true` to likely-PII columns. |
|
|
214
|
+
| `wlens mcp` | Start the MCP server for team / demo use. |
|
|
215
|
+
| `wlens mcp-proxy <url>` | Stdio↔HTTP bridge; used by Claude Desktop to reach a remote wlens. |
|
|
216
|
+
| `wlens clean` | Remove every file wlens installed in this repo. |
|
|
217
|
+
|
|
218
|
+
## Supported warehouses
|
|
219
|
+
|
|
220
|
+
| Warehouse | v0.1 | v0.2 |
|
|
221
|
+
|------------|:----:|:----:|
|
|
222
|
+
| DuckDB | ✅ | |
|
|
223
|
+
| Postgres | ✅ | |
|
|
224
|
+
| Redshift | ✅ | |
|
|
225
|
+
| BigQuery | | ⏳ |
|
|
226
|
+
| Snowflake | | ⏳ |
|
|
227
|
+
|
|
228
|
+
## PII handling
|
|
229
|
+
|
|
230
|
+
Sample rows committed to the repo go through two redaction layers:
|
|
231
|
+
|
|
232
|
+
1. **Explicit.** Any dbt column with `meta: pii: true` renders as `<pii>`.
|
|
233
|
+
2. **Regex safety net.** Column names matching built-in PII patterns
|
|
234
|
+
(`email`, `first_name`, `phone`, `ip_address`, etc.) are redacted
|
|
235
|
+
even without the flag.
|
|
236
|
+
|
|
237
|
+
Run `wlens tag-pii` to backfill the explicit flags (`--dry-run` to preview).
|
|
238
|
+
|
|
239
|
+
## Distribution tiers
|
|
240
|
+
|
|
241
|
+
wlens ships one binary, three escalating modes:
|
|
242
|
+
|
|
243
|
+
### 1. Solo — `wlens init` + `wlens generate`
|
|
244
|
+
|
|
245
|
+
Install wlens, point it at a dbt project, use Claude Code / Cursor /
|
|
246
|
+
Continue / Codex with the bundled skill + `wlens query`. Works today.
|
|
247
|
+
|
|
248
|
+
### 2. Demo a teammate — `wlens mcp --dangerously-share`
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
wlens mcp --dangerously-share
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Starts the wlens MCP server locally, opens an ngrok tunnel, auto-generates
|
|
255
|
+
a bearer token, and writes three drop-in files under `wlens/share/`:
|
|
256
|
+
|
|
257
|
+
- `wlens.mcpb` — double-click to install into Claude Desktop. mcp-remote
|
|
258
|
+
and Python deps are pre-bundled; recipient needs nothing beyond Claude.
|
|
259
|
+
- `claude_desktop_config.json` — paste into Claude Desktop's config if
|
|
260
|
+
you prefer editing by hand.
|
|
261
|
+
- `.mcp.json` — drop into a project root for Claude Code (native HTTP).
|
|
262
|
+
|
|
263
|
+
Dies when you Ctrl-C the process. The `--dangerously-` prefix is
|
|
264
|
+
deliberate: a public URL fronting a warehouse is not a production posture.
|
|
265
|
+
|
|
266
|
+
### 3. Team deployment — `wlens mcp` on your infra
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
export WLENS_AUTH_TOKEN=$(openssl rand -hex 32)
|
|
270
|
+
wlens mcp --port 8000 --allowed-host "*"
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Team deployments are **your infra's responsibility** — Railway / Fly /
|
|
274
|
+
Cloud Run / VPS / k8s. wlens doesn't ship Terraform or Helm. What it
|
|
275
|
+
does ship: bearer auth, `/health`, `/refresh` for CI-driven doc updates,
|
|
276
|
+
structured logging, fail-closed startup rules.
|
|
277
|
+
|
|
278
|
+
**Before you deploy, check:**
|
|
279
|
+
|
|
280
|
+
- **Read-only warehouse role.** Create a DB user with `SELECT`-only
|
|
281
|
+
grants. The in-app guard is defence in depth — the role is primary.
|
|
282
|
+
- **`WLENS_AUTH_TOKEN`.** Required. `wlens mcp` refuses to start on a
|
|
283
|
+
non-local bind without it.
|
|
284
|
+
- **TLS at the platform layer.** Your platform terminates TLS; wlens
|
|
285
|
+
binds plain HTTP behind it.
|
|
286
|
+
- **CI-driven docs refresh.** After dbt merges, have CI `POST /refresh`
|
|
287
|
+
so docs stay current without redeploying.
|
|
288
|
+
- **Talk to your platform team.** Auth, secrets, network policy — their
|
|
289
|
+
job, not wlens's.
|
|
290
|
+
|
|
291
|
+
See [`docs/mcp.md`](docs/mcp.md) for the full reference.
|
|
292
|
+
|
|
293
|
+
## Roadmap
|
|
294
|
+
|
|
295
|
+
- **v0.1** (current): dbt adapter; DuckDB + Postgres + Redshift
|
|
296
|
+
executors; `wlens init / generate / query / tag-pii / clean`; MCP
|
|
297
|
+
server (`wlens mcp`) with bearer auth, four tools, resources, prompts,
|
|
298
|
+
`/refresh` endpoint; `--dangerously-share` with `.mcpb` bundle + drop-in
|
|
299
|
+
config files; stdio↔HTTP proxy (`wlens mcp-proxy`).
|
|
300
|
+
- **v0.2**: sqlmesh adapter; BigQuery + Snowflake executors; Claude Code
|
|
301
|
+
plugin; Claude.ai-remote OAuth support.
|
|
302
|
+
|
|
303
|
+
## License
|
|
304
|
+
|
|
305
|
+
MIT.
|