Insight

Train small local prediction, clustering, anomaly-detection, and forecasting models over your own data, so a repeated question gets answered instantly and for free instead of reasoning from scratch every time.

The insight tool lets an agent turn your own verified data into a small model it trains and keeps, so a specific, repeated question (“will this patient deteriorate”, “will this lead convert”, “how many next week”) gets answered instantly, without a model call, once there’s enough history to learn from. Pepe picks the algorithm automatically, based on how much data actually exists; nothing to configure, nothing to tune.

This is not general machine learning research. It answers one question you define, from data you already have: a real, bounded capability, not open-ended discovery.

Four kinds of question

None of these types are specific to healthcare: the same classification pipeline works for a support team predicting whether a ticket will escalate or a clinic predicting readmission risk. What changes between the two is the target column and the columns used to predict it, not the kind of model.

In ML terms: classification, regression, and forecast are supervised learning, because the model learns from examples where the answer is already known. Clustering is the one unsupervised type here: there are no known answers or labeled examples, the model finds the groups on its own from the data.

Clustering doubles as anomaly detection for free: a row far from every group’s usual spread comes back flagged, the same model that did the grouping. A patient whose vitals put them nowhere near their usual peer group is exactly that kind of anomaly, worth a look before it becomes an emergency.

Where the data comes from

Two sources, chosen when you define what to predict:

Where it lives

A database connection’s rows are never copied anywhere: every training run and every row count queries the connection fresh, the same way db_query itself does. Only what to predict (target, feature columns, table name) is saved, not the data.

Imported rows are different: import_rows does persist them, in Pepe’s own local operational store (the same SQLite database commitments, watches, and traces already live in), capped at 50,000 rows per spec, oldest ones dropped first past that.

A trained model itself is a small binary (kilobytes, not megabytes) saved in that same local store, whichever source trained it. Losing that file just means the next prediction retrains from scratch; it holds nothing a human reads directly.

Not sure what to predict yet?

Ask to “analyze my data for insights” and, for a database connection, insight propose_targets samples real rows and suggests something for every kind of question Insight can answer, not just classification or regression: a low-cardinality column is a plausible category to classify, a numeric column with real spread is something to regress on, a name like status/risk/churn counts in its favor. When a table also has a column that looks like a date or timestamp, it pairs that with a numeric column to suggest a forecast (“track this over time”). And when a table has several numeric columns with real variation, it bundles them into a clustering suggestion (“group rows by these and see what natural clusters and outliers show up”), even with no target column in sight. It’s a heuristic, not a guarantee, and it never defines anything on its own - it’s a starting point to confirm, not a finished spec. This is meant for exactly the situation where someone has no idea what “predictable” even looks like in their own data: ask, and let Pepe point at real candidates instead of staring at a blank slate.

Defining what to predict

There’s no separate syntax to learn: describe what you want in the conversation, and the agent fills in the actual insight define call. For a classification/regression spec, name the target and which columns to predict it from: “predict whether a patient gets readmitted within 30 days, using age, length of stay, and prior admissions, from the discharges table in patients_prod.” A forecast spec names a time column instead of (or alongside) other columns: “forecast daily admission counts over the day column.” A clustering spec names no target at all, just what to group on: “group patients by age, comorbidity count, and prior admissions.”

Then insight import_rows (for an imported spec) or insight train_now (for either kind) once there’s enough history, and insight_predict for an answer, for the list of what’s defined, and for a spec’s model history. It’s a separate tool on purpose - insight (define/import_rows/train_now/delete) is the one that changes anything; insight_predict (predict/list/describe) only ever reads. That split means an operator can let an unattended surface (a cron job, a webhook) answer predictions on its own without also handing it the power to redefine or retrain what it’s predicting from.

How Pepe picks the algorithm

By default, never a manual choice: the model is picked from how much verified data actually exists, the same “figure it out” philosophy behind complexity-based routing:

One exception: the Windows binary ships with the first tier only. The libraries behind the other two publish nothing for Windows, and there is nothing to fix on our side. Everything Insight does still works there - a model for each of the four kinds of question, trained and answered the same way - Pepe just fits it with simple regression whatever the row count, and naming a missing family by hand says so plainly instead of failing halfway through training. On every other platform all three tiers are there as described.

A forecast is a regression underneath, with the timestamp turned into elapsed-time and day-of-week/month features automatically; the same three tiers apply. A model this large never trains on every row of a huge table: training uses a representative random sample (Postgres TABLESAMPLE, not just “the first N rows”, which would bias toward however the table happens to be ordered), capped at 200,000 rows. Past a certain point, more rows stop meaningfully improving a model this size.

An operator who already knows which algorithm they want can name it explicitly with define’s family (“linear”, “gbm”, or “neural”) instead of leaving it automatic - useful if they’ve already benchmarked their own data, or just want the one they’re used to. Leave it unset unless asked; automatic is the right default for almost everyone.

The accuracy or error number Pepe reports for a model comes from testing it against several different slices of the data, not just one - a steadier, more trustworthy number than checking against a single random slice would give, and closer to what the model will actually do on data it hasn’t seen yet. The model that actually answers predictions afterward is then trained fresh on everything available, not just the slice used to test it.

Retraining

Set retrain_interval_s on a spec and Pepe retrains it on its own once enough new rows have arrived (min_new_rows, default 50). A patient-risk model gets sharper as more discharges are recorded, without anyone re-running anything by hand. insight train_now retrains immediately regardless.

Retraining, on any schedule, costs nothing in model usage: it’s an internal timer checking whether it’s time and whether enough new rows arrived, and if so, fitting the model, plain computation from start to finish, the same as train_now itself. A model only costs anything at two separate moments: once, in conversation, when a person first describes what to predict, and later, only if something is built to turn a prediction into a written summary for a person to read (a scheduled check-in message, say) - the prediction itself, however often it retrains or gets queried, never needs one.

What it doesn’t do

Every model answers one question, defined up front, from structured data. A number works directly, and a column with a modest number of different values (up to 20, like a plan tier or a region) is turned into something the model can use automatically, no setup needed. A column with far more distinct values than that, like a customer ID, still can’t be used this way. It does not read free text (a discharge summary, a PDF chart); that data has to be turned into columns before Insight can use it. It doesn’t do time series with anything beyond a trend and weekly/yearly seasonality, and it doesn’t do image or audio. If a question needs judgment rather than a pattern in past data, that’s what the agent itself, reasoning turn by turn, is for.