brasil-cli-analyst · git:20260419.32e5018 · 2026-04-19 · sha256 0e0ddc4ea0c6422d

brasil-cli-analyst git:20260419.32e5018A

Immutable. This exact content never changes and is served at /api/v1/blob/0e0ddc4ea0c6422d.

---
name: brasil-cli-analyst
description: Use this skill whenever the task needs to answer a question about Brazil with local official microdata — PNADC trimestral, PNADC anual visita 5, Censo 2022, TSE eleitorado, IPCA, or salário mínimo — using the `brasil` / `pnad` CLI. Trigger for any state-level income analysis, household income-band distribution, annual income-source composition (labor vs benefits vs pensions vs capital), dashboard snapshot, SQLite query, or when a journalist / analyst / LLM agent needs a read-mostly, statistically auditable answer grounded in the repo's local outputs instead of writing ad-hoc pandas code.
---

# brasil-cli-analyst

Use the local `brasil` CLI (alias `pnad`) as the primary interface to Brazilian
official microdata in this repository. It produces labeled CSVs, SQLite tables,
a rich terminal dashboard, and machine-readable JSON payloads with bootstrap
confidence intervals on every estimate.

---

## when to trigger this skill

- The user asks about Brazilian **income, poverty, inequality, demographics,
  regional comparison, benefits, pensions, informal work, or PNADC
  microdata**.
- The user wants a **state-by-state (UF)** or **macro-region** breakdown.
- The user wants a **faixa de salário mínimo** cut (0-2, 2-5, 5-10, 10+ SM).
- The user wants an **annual decomposition** of income into work / benefits
  / previdência / capital.
- The user needs **95% confidence intervals** (bootstrap over IBGE replicate
  weights).
- The user wants a **local, reproducible** answer — no network calls required
  once data is synced.
- The answer will feed a **narrative, briefing, dashboard, or report**.

## when NOT to trigger this skill

- The user wants to analyze a dataset not in this repo (POF, Censo Demográfico
  microdata, RAIS, CAGED).
- The user wants real-time market data, news, or web research — use a
  WebSearch or a dedicated finance tool.
- The user just wants to *read* the existing `docs/artigo_pt.md` or
  `docs/index.html` — no CLI call needed.

---

## decision tree — pick the right subcommand

```
                         ┌─────────────────────────────────────┐
                         │  user question about Brazilian data │
                         └──────────────┬──────────────────────┘
                                        │
                      ┌─────────────────┴──────────────────┐
                      │                                    │
           broad / interpretive?                  precise / custom cut?
           ("paint me a picture")                 ("exact number for X")
                      │                                    │
                      ▼                                    ▼
       ┌─────────────────────────┐             ┌──────────────────────────┐
       │  brasil dashboard       │             │   is it a faixa de SM    │
       │  --format json          │             │      distribution?       │
       └─────────┬───────────────┘             └──────────┬───────────────┘
                 │                                        │
                 ▼                                        ▼
    need benefits/pensions split?                  YES           NO
           │                                         │            │
         YES     NO                                  ▼            ▼
           │     │                  ┌────────────────────┐  ┌────────────────┐
           ▼     ▼                  │ brasil             │  │ brasil query   │
    --mode anual \            dashboard default         │ renda-por-faixa-sm │  │ --sql "..."    │
    --composition-by-band \   (tri + anual)              │ --format json      │  │ --db ...sqlite │
    --dependency-ranking                                 │ --group-by uf|pais │  └────────────────┘
                                                        └────────────────────┘
```

**One-line rule of thumb:**

| If the question is about… | Use |
|---|---|
| a picture of the whole country | `brasil dashboard --format json` |
| faixas 0-2/2-5/5-10/10+ SM | `brasil renda-por-faixa-sm --format json` |
| an exact custom aggregate (avg, median, count) | `brasil query --sql "..."` |
| labor vs benefits vs pensions composition | `brasil dashboard --mode anual --composition-by-band --dependency-ranking --format json` |
| "with vs without benefits" sensitivity | `brasil dashboard --mode anual` (see *annual income lenses* below) |
| refreshing data | `brasil ibge-sync` then `brasil pipeline-run` / `brasil pipeline-run-anual` |

---

## canonical workflow

1. **Check artifacts first.** Before running anything heavy, verify that
   `data/outputs/brasil.sqlite` and `data/outputs/base_*_labeled_npv.csv`
   already exist. Do NOT re-run pipelines unless artifacts are missing or
   obviously stale.

2. **Inspect schema** with `PRAGMA table_info(...)` before writing SQL.
   Column names are verbose (`VD5001__rendim_domiciliar`), and casual
   guessing causes silent mismatches.

3. **Prefer JSON output** for anything that will be consumed by another
   agent or a dashboard. Human-formatted tables are harder to parse.

4. **Pass through CI fields** (`*_moe`, `*_ci_low`, `*_ci_high`) whenever you
   report a number — never strip them. Auditability is the point.

5. **Cite the weight column and vintage.** Every claim should be traceable
   to a specific weight (`V1028` / `V1032`), a specific target month (IPCA
   deflator), and a specific SM reference.

---

## the three primary subcommands in detail

### `brasil dashboard`

A rich nation + UF + macro-region summary with CI, Lorenz, bands, cross-tabs,
age pyramid, and (in annual mode) income-source composition. Best first
command when you don't yet know what you're looking for.

```bash
# auto-discover and combine trimestral + anual when both are built
brasil dashboard

# annual, with the premium breakdowns
brasil dashboard \
  --mode anual \
  --composition-by-band \
  --dependency-ranking \
  --format json
```

Annual-mode payload includes:

- `income_composition_national` — national breakdown by source
- `composition_by_band` — per-faixa breakdown by source
- `uf_dependency_ranking` — state ranking by (benefits + previdência) share
- `income_lenses_national` — total income / excluding benefits / excluding
  transfers / labor-only

### `brasil renda-por-faixa-sm`

Explicit band distribution with per-group CI. Use when the user wants the
exact shape of the distribution.

```bash
brasil renda-por-faixa-sm \
  --input data/outputs/base_labeled_npv.csv \
  --group-by uf \
  --uf-order renda_desc \
  --format json
```

### `brasil query`

Arbitrary read-only SQL. Use when the other two can't express the cut.

```bash
brasil query \
  --db data/outputs/brasil.sqlite \
  --sql "SELECT UF_label AS uf, \
                AVG(VD5001__rendim_domiciliar) AS avg_brl, \
                COUNT(DISTINCT dom_id) AS households \
         FROM base_anual_labeled_npv \
         GROUP BY 1 ORDER BY 2 DESC LIMIT 5"
```

**Do NOT** claim CI from arbitrary SQL — `query` does not compute bootstrap
variance.

---

## eight example questions → exact CLI

| # | Question | Command |
|---|---|---|
| 1 | "What's the average household income in the Federal District vs Maranhão?" | `brasil dashboard --mode anual --format json \| jq '.modes.alvo.top10_uf_income[0], .modes.alvo.bottom10_uf_income[-1]'` |
| 2 | "What percentage of Brazilians live on up to 2 minimum wages?" | `brasil renda-por-faixa-sm --group-by pais --format json \| jq '.groups[0].bands[] \| select(.range=="0-2")'` |
| 3 | "How concentrated is income in São Paulo?" | `brasil query --sql "SELECT 100.0*SUM(CASE WHEN VD5001__rendim_domiciliar>16210 THEN VD5001__rendim_domiciliar ELSE 0 END)/SUM(VD5001__rendim_domiciliar) AS share_top_band FROM base_anual_labeled_npv WHERE UF_label='São Paulo'"` |
| 4 | "Which states depend most on Bolsa Família and pensions?" | `brasil dashboard --mode anual --dependency-ranking --format json \| jq '.uf_dependency_ranking[:10]'` |
| 5 | "What is the Gini coefficient for Brazil?" | `brasil dashboard --format json \| jq '.modes.alvo.national.gini_household_sm'` |
| 6 | "How many households are in faixa 10+ SM and what's their share?" | `brasil renda-por-faixa-sm --group-by pais --format json \| jq '.groups[0].bands[] \| select(.range=="10+")'` |
| 7 | "Share of income coming from labor in each band" | `brasil dashboard --mode anual --composition-by-band --format json \| jq '.composition_by_band'` |
| 8 | "Most populous UFs by quarterly persons_total" | `brasil dashboard --format json \| jq '.modes.alvo.top10_uf_population[] \| {uf:.label, persons:.persons_total}'` |

---

## annual income lenses

When the user wants a "with vs without benefits" sensitivity, the annual
dashboard exposes these lenses in `income_lenses_national` and
`income_lenses_by_band`:

| lens | what it excludes |
|---|---|
| `renda_total` | nothing — total household income as reported |
| `sem_beneficios_sociais` | subtracts Bolsa Família, BPC, and other social benefits |
| `sem_transferencias_publicas` | subtracts all public transfers (benefits + pensions) |
| `somente_trabalho` | labor-only income (VD4020/VD4019 equivalent) |

Typical usage: compare `renda_total.gini` vs `somente_trabalho.gini` to quantify
how much redistribution the state is actually doing.

---

## methodology cheat sheet

- **Quarterly** labor income: `VD4020` (effective), fallback `VD4019`
  (habitual).
- **Annual** household income: `VD5001`, plus 8 source columns
  (`V5001A2..V5008A2`) and 4 composition lenses.
- **Household aggregation:** `dom_id = f"{Ano}{Trimestre}{UPA}{V1008}"`.
- **Weights:**
  - Quarterly primary: `V1028__peso_com_calibracao` (fallback `V1027`).
  - Annual primary: `V1032__peso_com_calibracao` (fallback `V1031`).
- **Replicate weights** for CI: `V1028001..V1028200` (trimestral) or
  `V1032001..V1032200` (anual). 200 replicates → bootstrap variance.
- **Deflator:** IPCA monthly index; target month defaults to the latest
  IPCA month, override with `--target YYYY-MM`.
- **SM reference:** BCB series 1619 (nominal monthly minimum wage).

---

## safety & guardrails

- `brasil query` is **read-only by default**. Writes require `--allow-write`.
- Default SQL parser rejects multi-statement queries.
- Claim uncertainty only when you computed it — do **not** attach a
  fabricated `± X` margin to a `query` result.
- When reporting a number publicly, include:
  - weight column actually used
  - replicate count actually found
  - IPCA target month
  - SM reference month
  - rows / households that entered the estimate
- Anything under `--unweighted` is **diagnostic only**, never publication.

---

## troubleshooting

| symptom | cause | fix |
|---|---|---|
| `brasil dashboard` shows `0 réplicas` | primary weight column didn't match any replicate prefix | check `--weight-col`, rebuild with `pipeline-run-anual` so `V1032xxx` is included |
| `unknown column VD5001` | querying `base_labeled_npv` (trimestral) instead of `base_anual_labeled_npv` | switch table |
| empty output for anual | `base_anual_labeled_npv.csv` not built | `brasil pipeline-run-anual --raw latest` |
| Gini reads 0.0 | all incomes were 0 (or weight column missing) | check `--weight-col` and filter predicate |
| deflated prices look wrong | `--target` month not in IPCA series | `brasil ibge-sync` to refresh `data/outputs/ipca.csv` |
| `brasil query` raises on CTE | mutli-statement SQL blocked | split into separate `--sql` calls |

---

## related skill

- `pnad-query` — thin sibling skill specialized in **ad-hoc SQL** with a
  column dictionary and the 10 most common safe queries pre-written.

## references in this skill

- `references/cli-cookbook.md` — extended CLI patterns and SQL recipes.
- `examples/prompts.md` — end-to-end LLM prompts that produce good results.