StackMap
Subscribe
Explore / fenic
typedef-ai

fenic

Semantic DataFrames: PySpark-style select, filter and join alongside AI operators — extract, classify, summarize, embed, semantic join — compiled on an engine built for inference.

665 41 Python Apache-2.0updated 3 days ago
View on GitHubDispute this mapping →
Curator's take

Use it when an agent's data discovery has to survive the chat: express the work as typed operators and the pipeline is already the artifact — `explain()`-able, rerunnable, row-level lineage, per-query cost and tokens, promotable to a table, view or MCP tool. `semantic.extract(PydanticModel)` replacing regex-plus-one-off-prompt is the whole pitch, and the engine handles batching, rate limits, retries and response caching so you aren't hand-rolling them. Not the tool for streaming or petabyte scale, and not a pandas replacement: it's a lazy query engine you configure models on, so single-row interactive work feels heavy and every operator is a real inference bill.

Mapped by ShipWithAI editors · links verified
README.md
fenic, by typedef

fenic: semantic DataFrames for humans and agents

PyPI version Python versions License Discord

fenic turns AI-assisted exploration of structured and unstructured data into reusable, inspectable DataFrame pipelines.

It's a DataFrame query engine for semantic data processing, with AI operators — extract, classify, summarize, embed, semantic join, and more — built into the query model. Use it to turn documents, transcripts, logs, eval traces, tickets, tables, and APIs into typed rows and repeatable workflows.

The point is a shift in what your data work produces. Humans and agents work on the same pipelines — both can author, inspect, and reuse them. The result isn't a one-off prompt or a brittle regex script that has to be reverse-engineered later — it's a durable artifact: typed, inspectable, rerunnable, and callable.

From exploration to artifact.

pip install fenic

Writing fenic with an AI coding agent? Run fenic skill install so Claude Code / Cursor / Codex write it correctly, and fenic check to lint it — details below.


What is fenic?

fenic is a semantic DataFrame engine. You write the PySpark/SQL-style operations you already know — select, filter, join, group_by, agg — alongside semantic operators that call language models as a first-class part of the query. You configure models once on a Session, build a pipeline lazily, and fenic compiles and runs it on a query engine built for inference: automatic batching, rate limiting, retries, token/cost accounting, and response caching.

Two ideas make it different from gluing an LLM onto pandas:

  • Inference lives inside the query model. Extraction, classification, summarization, and embeddings are operators with schemas and types — not side calls you orchestrate by hand.
  • The pipeline is the artifact. Because the work is expressed as typed operators, it's already inspectable (row-level lineage, explain, per-query metrics), rerunnable (lazy plans + caching), and promotable into a named table, view, or MCP tool an agent can call.

60 seconds: messy text → typed rows

Replace brittle parsing and one-off prompts with a typed, schema-bound operator. Define the shape you want as a Pydantic model; fenic returns structured columns you can query.

import fenic as fc
from pydantic import BaseModel, Field

class Ticket(BaseModel):
    product: str = Field(description="The product the user is asking about")
    sentiment: str = Field(description="positive, neutral, or negative")
    issue: str = Field(description="One-line summary of the user's problem")

session = fc.Session.get_or_create(
    fc.SessionConfig(
        app_name="quickstart",
        semantic=fc.SemanticConfig(
            language_models={
                "mini": fc.OpenAILanguageModel(model_name="gpt-4o-mini", rpm=500, tpm=200_000)
            },
        ),
    )
)

df = session.create_dataframe([
    {"id": 1, "text": "The CSV export in Reports keeps timing out since the last update."},
    {"id": 2, "text": "Love the new dashboard, but SSO login is broken on mobile."},
])

# Free text -> typed, queryable rows
tickets = (
    df.select("id", fc.semantic.extract("text", Ticket).

Continue your stack

What teams reach for next — and why each earns a place beside fenic. Ranked by curator confidence.