Local Mode
Local mode gives you a full HatiData warehouse on your machine, powered by an embedded DuckDB engine. Your data stays on disk, queries run in-process, and no network connection is required.
How hati init Works
Running hati init creates a .hati/ directory in your current project:
hati init
Initialized HatiData warehouse in .hati/
Database: .hati/warehouse.duckdb
Config: .hati/config.toml
Under the hood, this:
- Creates a DuckDB database file at
.hati/warehouse.duckdb - Generates a default
config.tomlwith sensible dev settings - Sets up a local cache directory for transpilation results
.hati/ Directory Structure
.hati/
config.toml # Runtime configuration
warehouse.duckdb # DuckDB database file
warehouse.duckdb.wal # DuckDB write-ahead log (transient)
cache/
transpile/ # Cached SQL transpilation results
query/ # Cached query results (L2 NVMe cache)
snapshots/ # Iceberg-format table snapshots (if enabled)
.hati/ to .gitignoreThe database file and cache contain your data. Do not commit them to source control.
Configuration Reference
The config.toml file controls how the local warehouse behaves:
[database]
path = "warehouse.duckdb"
memory_limit_mb = 4096 # DuckDB memory limit
threads = 4 # DuckDB execution threads
max_concurrent_queries = 100 # Concurrent query limit
[transpiler]
auto_transpile = true # Automatically rewrite Snowflake SQL
cache_enabled = true # Cache transpilation results
dialect = "snowflake" # Source SQL dialect
[cache]
l1_max_entries = 10000 # In-memory cache entries
l1_ttl_seconds = 300 # In-memory cache TTL
l2_enabled = true # Disk-based L2 cache
l2_max_size_mb = 1024 # L2 cache size limit
[dev]
dev_mode = true # Relaxed auth, verbose logging
tls_enabled = false # No TLS for local development
Running Queries Offline
In local mode, all queries execute against the embedded DuckDB engine without any network calls:
# Create tables
hati query "CREATE TABLE orders (id INT, customer_id INT, total DECIMAL(10,2), created_at TIMESTAMP)"
# Load data from files
hati query "INSERT INTO orders SELECT * FROM read_csv('orders.csv', auto_detect=true)"
# Query with Snowflake-compatible SQL
hati query "SELECT NVL(customer_id, 0) AS cid, SUM(total) FROM orders GROUP BY 1"
Using psql Locally
You can also start the proxy locally and connect with any Postgres client:
# Start the MCP server as a local proxy (port 5439)
hatidata-mcp-server --local --port 5439
# In another terminal, connect with psql
psql -h localhost -p 5439 -U admin -d hatidata
# Run queries interactively
hatidata=> SELECT COUNT(*) FROM orders;
hatidata=> SELECT * FROM information_schema.tables;
Using Python Locally
from hatidata_agent import HatiDataAgent
agent = HatiDataAgent(
host="localhost",
port=5439,
agent_id="dev-agent",
framework="custom",
)
rows = agent.query("SELECT * FROM orders LIMIT 10")
for row in rows:
print(row)
Using TypeScript Locally
import { HatiDataClient } from '@hatidata/sdk';
const client = new HatiDataClient({
host: 'localhost',
port: 5439,
agentId: 'dev-agent',
framework: 'custom',
});
await client.connect();
const rows = await client.query('SELECT * FROM orders LIMIT 10');
console.log(rows);
await client.close();
Data Stays on Your Machine
In local mode:
- The DuckDB database file is stored in
.hati/warehouse.duckdb - No data is sent to any cloud service
- No telemetry or metrics are collected
- The transpilation cache stores SQL rewrites on disk, not query results
- You can back up your data by copying the
.hati/directory
When you are ready to share your data or connect remote agents, use hati push --target cloud to migrate to Cloud Mode.
Loading Data
DuckDB's native file-reading functions work in local mode:
# CSV files
hati query "CREATE TABLE sales AS SELECT * FROM read_csv('sales.csv', auto_detect=true)"
# Parquet files
hati query "CREATE TABLE logs AS SELECT * FROM read_parquet('logs/*.parquet')"
# JSON files
hati query "CREATE TABLE events AS SELECT * FROM read_json('events.jsonl', auto_detect=true)"
Using with dbt
You can run dbt models against a local HatiData instance. Point your profiles.yml at localhost:
my_project:
target: dev
outputs:
dev:
type: hatidata
host: "localhost"
port: 5439
user: "admin"
password: ""
database: hatidata
schema: main
auto_transpile: true
threads: 4
Then run:
hatidata-mcp-server --local --port 5439 # Start the local proxy
dbt run # Run dbt models against local HatiData
See the dbt Adapter documentation for full configuration details.
Environment Variables
Local mode respects these environment variables when present:
| Variable | Default | Description |
|---|---|---|
HATIDATA_DEV_MODE | true | Enables relaxed auth and verbose logging |
HATIDATA_TLS_ENABLED | false | Enables TLS on the proxy |
HATIDATA_MEMORY_LIMIT_MB | 4096 | DuckDB memory limit |
HATIDATA_THREADS | 4 | DuckDB execution threads |
HATIDATA_MAX_CONCURRENT_QUERIES | 100 | Maximum concurrent queries |
HATIDATA_AI_HEALER_ENDPOINT | (unset) | URL for AI query healing on failure |
Environment variables override values in config.toml.
Next Steps
- Quickstart -- Initial setup walkthrough
- Cloud Mode -- Push your local warehouse to the cloud
- Core Concepts -- Architecture and query pipeline details
- SQL Compatibility -- Supported functions and types
- Python SDK -- Agent-aware database access for Python