Build something
people can feel.

shenas is an open-source personal analytics platform. Source plugins bring data in, transforms shape it, dashboards make it visible. Every piece is a plugin you can write, share, and improve.

Welcome

shenas connects to the services people already use -- Garmin, Strava, Spotify, Lunch Money, Google Calendar -- and syncs the data into a local encrypted database. Transforms normalize it into canonical metrics. Dashboards visualize it. The LLM coach asks questions of it.

Everything is a plugin. If there's a data source you care about, you can write a connector in an afternoon. If there's a way to visualize it, you can build a dashboard in a weekend.

Source plugins

Connect a new API or local file to shenas. dlt handles the pipeline; you define the tables.

Write one in 30 minutes →

Transform plugins

SQL, geofence, geocode, regex -- or write your own transform type.

Learn more →

Dashboard plugins

Lit web components that query Arrow IPC and render charts.

Learn more →

Dataset plugins

Define canonical metric schemas that transforms write into.

Learn more →

Write a source plugin in 30 minutes

A source plugin is a Python package that defines tables as dataclasses and extracts data from an API. dlt handles incremental loading, schema migration, and encryption. You focus on the API.

1

Scaffold the package

mkdir -p plugins/sources/myapi/shenas_sources/myapi
cd plugins/sources/myapi

# pyproject.toml
cat > pyproject.toml <<'EOF'
[project]
name = "shenas-source-myapi"
dependencies = ["dlt[duckdb]>=1.24.0", "shenas-source-core"]

[project.entry-points."shenas.sources"]
myapi = "shenas_sources.myapi.source:MyApiSource"
EOF
2

Define your tables

from shenas_sources.core.table import EventTable, Field
from typing import Annotated, Any, Iterator

class Activities(EventTable):
    class _Meta:
        name = "activities"
        display_name = "Activities"
        pk = ("id",)

    id: Annotated[str, Field(db_type="VARCHAR")] = ""
    name: Annotated[str, Field(db_type="VARCHAR")] = ""
    duration_s: Annotated[int, Field(db_type="INTEGER", unit="s")] = 0
    time_at: Annotated[str, Field(db_type="TIMESTAMP")] = ""

    @classmethod
    def extract(cls, client: Any, **ctx) -> Iterator[dict]:
        yield from client.get_activities()
3

Create the source class

from shenas_sources.core.source import Source

class MyApiSource(Source):
    name = "myapi"
    display_name = "My API"
    primary_table = "activities"

    def build_client(self):
        return MyApiClient(self.get_config_value("api_key"))

    def resources(self, client):
        from .tables import TABLES
        return [t.to_resource(client) for t in TABLES]
4

Install and sync

uv sync  # installs your plugin as a workspace member
shenasctl source myapi sync

Your data is now in a local encrypted DuckDB, queryable from dashboards and the LLM coach.

Other plugin types

Sources are the most common, but shenas has six plugin kinds. Each follows the same pattern: a Python package with an entry point.

Dataset Define canonical metric schemas (daily_hrv, transactions, events). Transforms write into these.
Transform SQL, geofence, geocode, regex extract, LLM categorize. Write your own by subclassing Transform.
Dashboard Lit web components that query via Arrow IPC. Charts, tables, timelines -- anything visual.
Frontend The entire UI shell is a plugin. Write your own minimal frontend or extend the default.
Theme CSS custom properties that pierce Shadow DOM. Ship a .css file and a Python class.
Analysis LLM-driven hypothesis modes. Define a system prompt, operation vocabulary, and recipe strategy.

Share your plugin

Plugins are standard Python wheels. Publish to PyPI and anyone can install with shenasctl source add myapi.

1

Build the wheel

cd plugins/sources/myapi
hatchling build
2

Publish to PyPI

twine upload dist/shenas_source_myapi-*.whl
3

Users install it

shenasctl source add myapi

The CLI verifies the Ed25519 signature (if you sign it), installs the wheel, and the plugin appears in the UI automatically.

Plugin certification

Plugins that meet our quality bar -- tests, documentation, no credential leaks, clean table schemas -- can apply for certified status. Certified plugins get a badge in the UI and are listed in the official plugin directory.

Apply for certification →