crude-analyst — briefing toolkit for the inner 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:
-
Pick the example shape that matches the question.
cat /usr/local/lib/python3.11/dist-packages/crude_analyst/examples/<shape>.pyQuestion 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.pyInvestigative, several themes multi_section.py -
Sanity-check the data with at most 3
run_sqlcalls (BATCH THEM in one assistant message — don't serialize). Usecrude_analyst.describe,date_range,peekto skip writing schema SQL by hand. -
Write
/tmp/briefing.pyby 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. -
Run it:
python3 /tmp/briefing.pyPrints "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_sqlis the only path. Do not trypsycopg2,psql,pg_dump, hunt for.envfiles, orpip installa 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.pymore 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
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 fromspot_pricescallout(label, query='SELECT count(*) AS n ...', value_template='{n} rigs')— query calloutline_chart(label, query=...)— query must alias columns asxandybar_chart(label, query=..., orientation='horizontal')— same shape as linetable(columns=[{key, label, align}], query=...)— query column keys must matchcommentary(text, tone='neutral|bullish|bearish|warning')
Composition
briefing(headline, tldr, widgets=[...])— flat: wraps in one sectionbriefing(headline, tldr, sections=[section(...), ...])— sectionedsection(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 withdate_truncand auto-bucketing per the palette rulerolling(col, window=10, fn='AVG', order_col='price_date')— fragmentpct_change(col, periods=1, order_col='date')— fragmenttop_n(table=, group_by=, order_by='SUM(x)', n=10, where=)— full SELECTthreshold_events(table=, date_col=, value_col=, rolling_window=, threshold_pct=)— full SELECT; returns event_start, event_peak, start_value, peak_value, pct_movelast_n_days(date_col, 90),between(date_col, '2024-01-01', '2024-12-31')— fragmentsdescribe(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/)
Metadata
Release files for crudecode-analyst 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| crudecode_analyst-0.5.0.tar.gz | 17.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| crudecode_analyst-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.5 kB
Release files / crudecode_analyst-0.5.0.tar.gz
| Download URL | crudecode_analyst-0.5.0.tar.gz |
|---|---|
| Size | 17.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5d62f1ecf9387472871eae91f4b19b42f4b4f248a7eb3c6b1a59de3677c0b9ca
|
|
BLAKE2b-256 checksum How to use checksums |
0ee7f551598c106600dbc072989d1e2f67fd97afaa597f0443f86a036bb1e3d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|
Release files / crudecode_analyst-0.5.0-py3-none-any.whl
| Download URL | crudecode_analyst-0.5.0-py3-none-any.whl |
|---|---|
| Size | 28.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
00a42e6cce6c60b786755236ec79d073872cd9dc0e335f83b432d2a40eeec22c
|
|
BLAKE2b-256 checksum How to use checksums |
b23ec644d766fe7648830094580f8e59e390df8fa6f5884a992c9635ace3b6fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|