Metadata-Version: 2.4
Name: crudecode-analyst
Version: 0.3.0
Summary: Briefing toolkit for Crude Code inner agents — widget builders, SQL helpers, and worked example templates.
Project-URL: Homepage, https://github.com/petroleumPythoneer/crudecode
Author: Crude Code
License-Expression: MIT
License-File: LICENSE
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.11
Description-Content-Type: text/markdown

# crude-analyst — briefing toolkit for the data analyst agent

A composer for oil & gas briefings. Read this whole file before composing
any briefing — most questions can be answered in 4-5 tool calls if you
follow the loop below.

## The loop

For every question, do this:

1. **Pick the example shape that matches the question.**
   ```bash
   cat /usr/local/lib/python3.11/dist-packages/crude_analyst/examples/<shape>.py
   ```
   | Question shape                       | Example file            |
   |--------------------------------------|-------------------------|
   | "What is X right now"                | `snapshot.py`           |
   | "How has X changed over T"           | `trend.py`              |
   | "Top N by metric"                    | `ranking.py`            |
   | "X vs Y"                             | `comparison.py`         |
   | "Find rows where X happens"          | `detection.py`          |
   | Investigative, several themes        | `multi_section.py`      |

2. **Sanity-check the data** with at most 3 `run_sql` calls (BATCH THEM
   in one assistant message — don't serialize). Use `crude_analyst.describe`,
   `date_range`, `peek` to skip writing schema SQL by hand.

3. **Write `/tmp/briefing.py`** by copying the example and editing the
   CONFIG block + headline/tldr/commentary. Use the file editor tool
   (`str_replace_based_edit_tool`) for clean multi-line writes — DO NOT
   use bash heredocs for the briefing script; quoting will bite you.

4. **Run it:**
   ```bash
   python3 /tmp/briefing.py
   ```
   Prints "Saved." on success, or `PERSIST_ERROR: 422 {widgets: [...]}`
   if a widget query failed. Read the error, fix the query, re-run.

That's the loop. **4-5 tool calls total.** If you're past 8 you're
over-exploring.

## Hard rules

- **The sandbox cannot connect to the database.** `run_sql` is the only
  path. Do not try `psycopg2`, `psql`, `pg_dump`, hunt for `.env` files,
  or `pip install` a DB driver — none of it works.
- **Widgets carry SQL strings.** The server runs the SQL after you
  persist. You do not need to (and should not) compute final result
  rows in this sandbox.
- **One bash call should compose + persist.** If you're regenerating
  the whole `/tmp/briefing.py` more than twice, stop and read the
  example again.
- **`persist()` reads the URL from `$CRUDE_PERSIST_URL`.** Don't
  hardcode it.

## Public API at a glance

```python
from crude_analyst import (
    # Widget builders
    callout, table, line_chart, bar_chart, commentary,
    # Composition
    section, briefing, error,
    # I/O
    persist, PersistError,
    # SQL: time-series
    bucket_time, auto_granularity,
    # SQL: window functions
    rolling, lag, lead, pct_change,
    # SQL: filters (compose with AND)
    last_n_days, last_n_months, last_n_years, ytd, between,
    # SQL: ranking
    top_n,
    # SQL: event detection
    threshold_events,
    # SQL: schema introspection
    describe, date_range, peek,
)
```

Every function has docstring docs (`help(crude_analyst.X)`).

## What each layer does

### Mechanical (widget builders)
Build validated widget dicts. Each builder enforces the spec shape — no
domain knowledge.

- `callout(label, code='WTI_USD')` — commodity callout from `spot_prices`
- `callout(label, query='SELECT count(*) AS n ...', value_template='{n} rigs')` — query callout
- `line_chart(label, query=...)` — query must alias columns as `x` and `y`
- `bar_chart(label, query=..., orientation='horizontal')` — same shape as line
- `table(columns=[{key, label, align}], query=...)` — query column keys must match
- `commentary(text, tone='neutral|bullish|bearish|warning')`

### Composition

- `briefing(headline, tldr, widgets=[...])` — flat: wraps in one section
- `briefing(headline, tldr, sections=[section(...), ...])` — sectioned
- `section(label, layout, widgets)` — layouts: `full-width`, `3-col`, `2-col`

### SQL builders (return strings — drop into `query=`)

- `bucket_time(table=, date_col=, value_cols={col: fn}, days_back=, granularity='auto')`
  — full SELECT with `date_trunc` and auto-bucketing per the palette rule
- `rolling(col, window=10, fn='AVG', order_col='price_date')` — fragment
- `pct_change(col, periods=1, order_col='date')` — fragment
- `top_n(table=, group_by=, order_by='SUM(x)', n=10, where=)` — full SELECT
- `threshold_events(table=, date_col=, value_col=, rolling_window=, threshold_pct=)`
  — full SELECT; returns event_start, event_peak, start_value, peak_value, pct_move
- `last_n_days(date_col, 90)`, `between(date_col, '2024-01-01', '2024-12-31')` — fragments
- `describe(table)`, `date_range(table, date_col)`, `peek(table, n=5)` — full SELECTs

### Examples

Six runnable templates in `crude_analyst/examples/`. Pick by shape,
not topic.

## When examples don't fit

For unusual question shapes, compose by hand using the widget + SQL
helpers above. The examples are starting points, not the only allowed
shapes. But: **first try to fit the question into one of the six.**
Most questions do.

## Where it runs

The Managed Agents data-analyst sandbox installs this package from PyPI
at environment build time. The agent imports it inside the sandbox to
compose briefing specs and POST them to the persist endpoint.

## Source

<https://github.com/petroleumPythoneer/crudecode> (`packages/crude-analyst/`)
