[{"data":1,"prerenderedAt":6852},["ShallowReactive",2],{"tutorial-stock-analyst-101/scaffold-template":3,"content-query-5Z6yGgM2MV":1036,"content-query-15H3dABhhV":1825},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"readingTime":11,"category":12,"tags":13,"difficulty":17,"module":5,"step":18,"journeys":19,"roles":21,"learnMore":24,"author":34,"body":38,"_type":519,"_id":1031,"_source":1032,"_file":1033,"_stem":1034,"_extension":1035},"/tutorials/stock-analyst-101/scaffold-template","stock-analyst-101",false,"","Scaffold Your Project","Create an empty Bruin project with DuckDB as the local database - the workspace your fundamentals, prices, and macro data will land into.","2026-04-24",5,"Tutorial",[14,15,16],"Bruin CLI","Bruin AI","DuckDB","Beginner",2,[20],"Stock Analyst",[22,23],"Finance","Data Analyst",[25,28,31],{"label":26,"url":27},"Bruin init command","https://getbruin.com/docs/bruin/commands/init.html",{"label":29,"url":30},"Bruin templates tutorial","/learn/bruin-templates",{"label":32,"url":33},"DuckDB platform docs","https://getbruin.com/docs/bruin/platforms/duckdb.html",{"name":35,"role":36,"image":37},"Bruin Team","Bruin Data","/bruin-logo-2025.svg",{"type":39,"children":40,"toc":1020},"root",[41,50,72,78,83,140,145,151,156,197,202,246,252,257,268,273,289,300,312,419,424,437,457,462,969,996,1002,1014],{"type":42,"tag":43,"props":44,"children":46},"element","h2",{"id":45},"what-youll-do",[47],{"type":48,"value":49},"text","What you'll do",{"type":42,"tag":51,"props":52,"children":53},"p",{},[54,56,62,64,70],{"type":48,"value":55},"Ask your AI agent to create a Bruin project called ",{"type":42,"tag":57,"props":58,"children":60},"code",{"className":59},[],[61],{"type":48,"value":5},{"type":48,"value":63}," with a local DuckDB database as the destination, then seed an ",{"type":42,"tag":57,"props":65,"children":67},{"className":66},[],[68],{"type":48,"value":69},"AGENTS.md",{"type":48,"value":71}," file at the project root with the Bruin rules the agent should follow in every future session.",{"type":42,"tag":43,"props":73,"children":75},{"id":74},"why-this-step-matters",[76],{"type":48,"value":77},"Why this step matters",{"type":42,"tag":51,"props":79,"children":80},{},[81],{"type":48,"value":82},"A Bruin project is a folder on your laptop that holds:",{"type":42,"tag":84,"props":85,"children":86},"ul",{},[87,109,121],{"type":42,"tag":88,"props":89,"children":90},"li",{},[91,93,99,101,107],{"type":48,"value":92},"A ",{"type":42,"tag":94,"props":95,"children":96},"strong",{},[97],{"type":48,"value":98},"config file",{"type":48,"value":100}," (",{"type":42,"tag":57,"props":102,"children":104},{"className":103},[],[105],{"type":48,"value":106},".bruin.yml",{"type":48,"value":108},") - where your API keys and database connection live",{"type":42,"tag":88,"props":110,"children":111},{},[112,114,119],{"type":48,"value":113},"An ",{"type":42,"tag":94,"props":115,"children":116},{},[117],{"type":48,"value":118},"assets folder",{"type":48,"value":120}," - where the rules for pulling data will go (FMP, Yahoo, FRED assets)",{"type":42,"tag":88,"props":122,"children":123},{},[124,125,130,132,138],{"type":48,"value":92},{"type":42,"tag":94,"props":126,"children":127},{},[128],{"type":48,"value":129},"DuckDB file",{"type":48,"value":131}," - the database itself, which is just a single ",{"type":42,"tag":57,"props":133,"children":135},{"className":134},[],[136],{"type":48,"value":137},".duckdb",{"type":48,"value":139}," file on your disk",{"type":42,"tag":51,"props":141,"children":142},{},[143],{"type":48,"value":144},"DuckDB is the key choice here. It's a database that lives entirely in a file - no server to run, no cloud account to create, no credit card. It behaves like Postgres or BigQuery but all the data sits on your laptop. Perfect for learning, perfect for personal investing research.",{"type":42,"tag":43,"props":146,"children":148},{"id":147},"prompt-the-agent",[149],{"type":48,"value":150},"Prompt the agent",{"type":42,"tag":51,"props":152,"children":153},{},[154],{"type":48,"value":155},"Open your AI coding tool in an empty folder you'd like to use as your workspace, and paste this prompt:",{"type":42,"tag":157,"props":158,"children":159},"prompt-block",{},[160],{"type":42,"tag":51,"props":161,"children":162},{},[163,165,171,173,179,181,187,189,195],{"type":48,"value":164},"Using Bruin MCP, run ",{"type":42,"tag":57,"props":166,"children":168},{"className":167},[],[169],{"type":48,"value":170},"bruin init empty stock-analyst-101",{"type":48,"value":172}," to scaffold a new pipeline from the empty template. Then add a DuckDB connection called ",{"type":42,"tag":57,"props":174,"children":176},{"className":175},[],[177],{"type":48,"value":178},"duckdb-default",{"type":48,"value":180}," pointing to ",{"type":42,"tag":57,"props":182,"children":184},{"className":183},[],[185],{"type":48,"value":186},"./stock-analyst-101/stock.duckdb",{"type":48,"value":188},". Finally, run ",{"type":42,"tag":57,"props":190,"children":192},{"className":191},[],[193],{"type":48,"value":194},"bruin connections test --name duckdb-default",{"type":48,"value":196}," and show me the output.",{"type":42,"tag":51,"props":198,"children":199},{},[200],{"type":48,"value":201},"The agent will:",{"type":42,"tag":203,"props":204,"children":205},"ol",{},[206,216,241],{"type":42,"tag":88,"props":207,"children":208},{},[209,211],{"type":48,"value":210},"Run ",{"type":42,"tag":57,"props":212,"children":214},{"className":213},[],[215],{"type":48,"value":170},{"type":42,"tag":88,"props":217,"children":218},{},[219,221,226,228,234,236],{"type":48,"value":220},"Edit ",{"type":42,"tag":57,"props":222,"children":224},{"className":223},[],[225],{"type":48,"value":106},{"type":48,"value":227}," to add a ",{"type":42,"tag":57,"props":229,"children":231},{"className":230},[],[232],{"type":48,"value":233},"duckdb",{"type":48,"value":235}," connection block pointing at ",{"type":42,"tag":57,"props":237,"children":239},{"className":238},[],[240],{"type":48,"value":186},{"type":42,"tag":88,"props":242,"children":243},{},[244],{"type":48,"value":245},"Run the test command to confirm the connection works",{"type":42,"tag":43,"props":247,"children":249},{"id":248},"what-the-agent-just-created",[250],{"type":48,"value":251},"What the agent just created",{"type":42,"tag":51,"props":253,"children":254},{},[255],{"type":48,"value":256},"Your folder now looks like this:",{"type":42,"tag":258,"props":259,"children":263},"pre",{"className":260,"code":262,"language":48},[261],"language-text","./                              # current folder\n├── .bruin.yml                  # project config - holds API keys + connections\n└── stock-analyst-101/          # the pipeline\n    ├── pipeline.yml            # pipeline config\n    ├── assets/                 # where ingestion rules will live (empty for now)\n    │   └── empty.sql           # placeholder - safe to delete\n    └── stock.duckdb            # the database (created on first write)\n",[264],{"type":42,"tag":57,"props":265,"children":266},{"__ignoreMap":7},[267],{"type":48,"value":262},{"type":42,"tag":51,"props":269,"children":270},{},[271],{"type":48,"value":272},"Ask the agent to delete the placeholder:",{"type":42,"tag":157,"props":274,"children":275},{},[276],{"type":42,"tag":51,"props":277,"children":278},{},[279,281,287],{"type":48,"value":280},"Remove ",{"type":42,"tag":57,"props":282,"children":284},{"className":283},[],[285],{"type":48,"value":286},"stock-analyst-101/assets/empty.sql",{"type":48,"value":288}," - I'll add real assets next step.",{"type":42,"tag":43,"props":290,"children":292},{"id":291},"peek-inside-bruinyml",[293,295],{"type":48,"value":294},"Peek inside ",{"type":42,"tag":57,"props":296,"children":298},{"className":297},[],[299],{"type":48,"value":106},{"type":42,"tag":51,"props":301,"children":302},{},[303,305,310],{"type":48,"value":304},"Have the agent show you ",{"type":42,"tag":57,"props":306,"children":308},{"className":307},[],[309],{"type":48,"value":106},{"type":48,"value":311},". You should see something like:",{"type":42,"tag":258,"props":313,"children":317},{"className":314,"code":315,"language":316,"meta":7,"style":7},"language-yaml shiki shiki-themes github-dark","environments:\n  default:\n    connections:\n      duckdb:\n        - name: \"duckdb-default\"\n          path: \"./stock-analyst-101/stock.duckdb\"\n","yaml",[318],{"type":42,"tag":57,"props":319,"children":320},{"__ignoreMap":7},[321,339,351,364,377,401],{"type":42,"tag":322,"props":323,"children":326},"span",{"class":324,"line":325},"line",1,[327,333],{"type":42,"tag":322,"props":328,"children":330},{"style":329},"--shiki-default:#85E89D",[331],{"type":48,"value":332},"environments",{"type":42,"tag":322,"props":334,"children":336},{"style":335},"--shiki-default:#E1E4E8",[337],{"type":48,"value":338},":\n",{"type":42,"tag":322,"props":340,"children":341},{"class":324,"line":18},[342,347],{"type":42,"tag":322,"props":343,"children":344},{"style":329},[345],{"type":48,"value":346},"  default",{"type":42,"tag":322,"props":348,"children":349},{"style":335},[350],{"type":48,"value":338},{"type":42,"tag":322,"props":352,"children":354},{"class":324,"line":353},3,[355,360],{"type":42,"tag":322,"props":356,"children":357},{"style":329},[358],{"type":48,"value":359},"    connections",{"type":42,"tag":322,"props":361,"children":362},{"style":335},[363],{"type":48,"value":338},{"type":42,"tag":322,"props":365,"children":367},{"class":324,"line":366},4,[368,373],{"type":42,"tag":322,"props":369,"children":370},{"style":329},[371],{"type":48,"value":372},"      duckdb",{"type":42,"tag":322,"props":374,"children":375},{"style":335},[376],{"type":48,"value":338},{"type":42,"tag":322,"props":378,"children":379},{"class":324,"line":11},[380,385,390,395],{"type":42,"tag":322,"props":381,"children":382},{"style":335},[383],{"type":48,"value":384},"        - ",{"type":42,"tag":322,"props":386,"children":387},{"style":329},[388],{"type":48,"value":389},"name",{"type":42,"tag":322,"props":391,"children":392},{"style":335},[393],{"type":48,"value":394},": ",{"type":42,"tag":322,"props":396,"children":398},{"style":397},"--shiki-default:#9ECBFF",[399],{"type":48,"value":400},"\"duckdb-default\"\n",{"type":42,"tag":322,"props":402,"children":404},{"class":324,"line":403},6,[405,410,414],{"type":42,"tag":322,"props":406,"children":407},{"style":329},[408],{"type":48,"value":409},"          path",{"type":42,"tag":322,"props":411,"children":412},{"style":335},[413],{"type":48,"value":394},{"type":42,"tag":322,"props":415,"children":416},{"style":397},[417],{"type":48,"value":418},"\"./stock-analyst-101/stock.duckdb\"\n",{"type":42,"tag":51,"props":420,"children":421},{},[422],{"type":48,"value":423},"This file is your control panel. Every API key you add (FMP, FRED) will live here too. It's local, git-ignored by default, and never leaves your machine.",{"type":42,"tag":43,"props":425,"children":427},{"id":426},"seed-agentsmd-with-bruin-rules",[428,430,435],{"type":48,"value":429},"Seed ",{"type":42,"tag":57,"props":431,"children":433},{"className":432},[],[434],{"type":48,"value":69},{"type":48,"value":436}," with Bruin rules",{"type":42,"tag":51,"props":438,"children":439},{},[440,442,447,449,455],{"type":48,"value":441},"Any AI coding tool (Claude Code, Cursor, Codex) automatically reads an ",{"type":42,"tag":57,"props":443,"children":445},{"className":444},[],[446],{"type":48,"value":69},{"type":48,"value":448}," at the project root whenever the workspace opens. This is where you tell the agent ",{"type":42,"tag":450,"props":451,"children":452},"em",{},[453],{"type":48,"value":454},"how to work",{"type":48,"value":456}," in this project - before it ever touches your data.",{"type":42,"tag":51,"props":458,"children":459},{},[460],{"type":48,"value":461},"Prompt the agent:",{"type":42,"tag":157,"props":463,"children":464},{},[465,515],{"type":42,"tag":51,"props":466,"children":467},{},[468,470,475,477,482,484,490,492,498,500,505,507,513],{"type":48,"value":469},"Create an ",{"type":42,"tag":57,"props":471,"children":473},{"className":472},[],[474],{"type":48,"value":69},{"type":48,"value":476}," at the root of this workspace (next to ",{"type":42,"tag":57,"props":478,"children":480},{"className":479},[],[481],{"type":48,"value":106},{"type":48,"value":483},") with the content below, then show me the file after creation. Also ask me whether I want you to scaffold separate ",{"type":42,"tag":57,"props":485,"children":487},{"className":486},[],[488],{"type":48,"value":489},"dev",{"type":48,"value":491}," and ",{"type":42,"tag":57,"props":493,"children":495},{"className":494},[],[496],{"type":48,"value":497},"prod",{"type":48,"value":499}," environments in ",{"type":42,"tag":57,"props":501,"children":503},{"className":502},[],[504],{"type":48,"value":106},{"type":48,"value":506},", or keep a single ",{"type":42,"tag":57,"props":508,"children":510},{"className":509},[],[511],{"type":48,"value":512},"default",{"type":48,"value":514}," environment for now - wait for my answer before making any changes to environments.",{"type":42,"tag":258,"props":516,"children":520},{"className":517,"code":518,"language":519,"meta":7,"style":7},"language-markdown shiki shiki-themes github-dark","# AGENTS.md\n\n## How you (the AI agent) should work in this project\n\n### Ground rules\n- This is a Bruin project. Use the **Bruin MCP** tools when available - they're the fastest, most reliable path\n- Use the **Bruin CLI** for all pipeline operations: `bruin init`, `bruin run`, `bruin validate`, `bruin query`, `bruin ai enhance`, `bruin connections test`\n- Reference the **[Bruin docs](https://getbruin.com/docs)** when unsure about asset types, materializations, connection configs, or CLI flags. Don't guess - the docs are authoritative\n- **Ask me when unclear.** If a request is ambiguous (time range, columns, grain, attribution model, which environment, etc.), ask before guessing. A clarifying question now beats a wrong answer later\n\n### Environments\n- Before adding or changing connections, confirm with me whether this project uses a single `default` environment or separate `dev` / `prod` environments\n- Never copy secrets between environments without asking\n- Keep env-specific values (DB paths, API keys, schemas) scoped to the right environment block\n\n### Cap data volume when testing\n- For exploratory queries, use `LIMIT 20` (or fewer) until you've confirmed the shape of the result\n- For ingestr assets during testing, use Bruin's **interval dates** (`interval_start`, `interval_end`) to cap the backfill window - never pull unbounded history on a first run\n- Prefer **narrow, explicit date windows** (e.g. last 7 days) over open-ended scans\n\n### Validate before you run\n- Run `bruin validate \u003Cpath>` before `bruin run` - it catches YAML errors, missing connections, broken refs, and type mismatches without burning compute\n- If validation fails, read the error, fix the root cause at the source, then re-validate. Do not chain `run` attempts hoping they work\n- After running, do **spot checks across layers**: row counts, date min/max, null counts, and a handful of sample rows at each tier (raw → staging → marts). A pipeline that \"succeeded\" can still have silently wrong data\n\n### Document as you add\n- Every asset: **top-level description** explaining what it produces and why\n- Every meaningful column: **column-level description**. Don't let `cost_micros`, `status_code`, or `price_adj` go undocumented\n- Add **tags** to group assets (e.g. `tier:raw`, `domain:finance`, `owner:analyst`)\n- Add **quality checks** (`not_null`, `unique`, `accepted_values`, `positive`) on columns where the invariant matters\n- Add **custom checks** (SQL-backed assertions) for business rules that can't be expressed at the column level\n- Add **metadata** (owner, source system, refresh cadence, SLA) so future-you and future-agents have context\n\n### Keep this file current\n- When you learn a non-obvious fact about the data, a convention the user prefers, or a mistake worth avoiding - **append it to this file**. That's how the agent gets smarter across sessions\n\n### Naming and structure\n- Schemas: `raw.*` for ingestion output, `staging.*` for cleaned/typed, `marts.*` for business-ready tables\n- Asset file names should match the table they produce (e.g. `raw.fmp_fundamentals` → `fmp_fundamentals.asset.yml`)\n- Keep SQL assets under `\u003Cpipeline>/assets/`, same folder as ingestr assets\n- SQL assets should be **idempotent** - re-running produces the same output\n\n### Safety\n- **Never commit `.bruin.yml`.** It holds secrets. It's git-ignored by default; verify before staging\n- **Never run `DROP`, `DELETE`, `TRUNCATE`, or `UPDATE`** on raw tables - they're the ingestion output and should be rebuilt via `bruin run`, not mutated\n- When I say \"reset\" or \"start over\", ask me exactly what to drop before dropping anything\n\n### Show your work\n- Before running a command that modifies files or data, show the plan and wait for approval\n- Print the SQL before executing it\n- When editing YAML, show the final file or a diff - not just \"done\"\n","markdown",[521],{"type":42,"tag":57,"props":522,"children":523},{"__ignoreMap":7},[524,532,541,549,556,564,572,581,590,599,607,616,625,634,643,651,660,669,678,687,695,704,713,722,731,739,748,757,766,775,784,793,802,810,819,828,836,845,854,863,872,881,889,898,907,916,925,933,942,951,960],{"type":42,"tag":322,"props":525,"children":526},{"class":324,"line":325},[527],{"type":42,"tag":322,"props":528,"children":529},{},[530],{"type":48,"value":531},"# AGENTS.md\n",{"type":42,"tag":322,"props":533,"children":534},{"class":324,"line":18},[535],{"type":42,"tag":322,"props":536,"children":538},{"emptyLinePlaceholder":537},true,[539],{"type":48,"value":540},"\n",{"type":42,"tag":322,"props":542,"children":543},{"class":324,"line":353},[544],{"type":42,"tag":322,"props":545,"children":546},{},[547],{"type":48,"value":548},"## How you (the AI agent) should work in this project\n",{"type":42,"tag":322,"props":550,"children":551},{"class":324,"line":366},[552],{"type":42,"tag":322,"props":553,"children":554},{"emptyLinePlaceholder":537},[555],{"type":48,"value":540},{"type":42,"tag":322,"props":557,"children":558},{"class":324,"line":11},[559],{"type":42,"tag":322,"props":560,"children":561},{},[562],{"type":48,"value":563},"### Ground rules\n",{"type":42,"tag":322,"props":565,"children":566},{"class":324,"line":403},[567],{"type":42,"tag":322,"props":568,"children":569},{},[570],{"type":48,"value":571},"- This is a Bruin project. Use the **Bruin MCP** tools when available - they're the fastest, most reliable path\n",{"type":42,"tag":322,"props":573,"children":575},{"class":324,"line":574},7,[576],{"type":42,"tag":322,"props":577,"children":578},{},[579],{"type":48,"value":580},"- Use the **Bruin CLI** for all pipeline operations: `bruin init`, `bruin run`, `bruin validate`, `bruin query`, `bruin ai enhance`, `bruin connections test`\n",{"type":42,"tag":322,"props":582,"children":584},{"class":324,"line":583},8,[585],{"type":42,"tag":322,"props":586,"children":587},{},[588],{"type":48,"value":589},"- Reference the **[Bruin docs](https://getbruin.com/docs)** when unsure about asset types, materializations, connection configs, or CLI flags. Don't guess - the docs are authoritative\n",{"type":42,"tag":322,"props":591,"children":593},{"class":324,"line":592},9,[594],{"type":42,"tag":322,"props":595,"children":596},{},[597],{"type":48,"value":598},"- **Ask me when unclear.** If a request is ambiguous (time range, columns, grain, attribution model, which environment, etc.), ask before guessing. A clarifying question now beats a wrong answer later\n",{"type":42,"tag":322,"props":600,"children":602},{"class":324,"line":601},10,[603],{"type":42,"tag":322,"props":604,"children":605},{"emptyLinePlaceholder":537},[606],{"type":48,"value":540},{"type":42,"tag":322,"props":608,"children":610},{"class":324,"line":609},11,[611],{"type":42,"tag":322,"props":612,"children":613},{},[614],{"type":48,"value":615},"### Environments\n",{"type":42,"tag":322,"props":617,"children":619},{"class":324,"line":618},12,[620],{"type":42,"tag":322,"props":621,"children":622},{},[623],{"type":48,"value":624},"- Before adding or changing connections, confirm with me whether this project uses a single `default` environment or separate `dev` / `prod` environments\n",{"type":42,"tag":322,"props":626,"children":628},{"class":324,"line":627},13,[629],{"type":42,"tag":322,"props":630,"children":631},{},[632],{"type":48,"value":633},"- Never copy secrets between environments without asking\n",{"type":42,"tag":322,"props":635,"children":637},{"class":324,"line":636},14,[638],{"type":42,"tag":322,"props":639,"children":640},{},[641],{"type":48,"value":642},"- Keep env-specific values (DB paths, API keys, schemas) scoped to the right environment block\n",{"type":42,"tag":322,"props":644,"children":646},{"class":324,"line":645},15,[647],{"type":42,"tag":322,"props":648,"children":649},{"emptyLinePlaceholder":537},[650],{"type":48,"value":540},{"type":42,"tag":322,"props":652,"children":654},{"class":324,"line":653},16,[655],{"type":42,"tag":322,"props":656,"children":657},{},[658],{"type":48,"value":659},"### Cap data volume when testing\n",{"type":42,"tag":322,"props":661,"children":663},{"class":324,"line":662},17,[664],{"type":42,"tag":322,"props":665,"children":666},{},[667],{"type":48,"value":668},"- For exploratory queries, use `LIMIT 20` (or fewer) until you've confirmed the shape of the result\n",{"type":42,"tag":322,"props":670,"children":672},{"class":324,"line":671},18,[673],{"type":42,"tag":322,"props":674,"children":675},{},[676],{"type":48,"value":677},"- For ingestr assets during testing, use Bruin's **interval dates** (`interval_start`, `interval_end`) to cap the backfill window - never pull unbounded history on a first run\n",{"type":42,"tag":322,"props":679,"children":681},{"class":324,"line":680},19,[682],{"type":42,"tag":322,"props":683,"children":684},{},[685],{"type":48,"value":686},"- Prefer **narrow, explicit date windows** (e.g. last 7 days) over open-ended scans\n",{"type":42,"tag":322,"props":688,"children":690},{"class":324,"line":689},20,[691],{"type":42,"tag":322,"props":692,"children":693},{"emptyLinePlaceholder":537},[694],{"type":48,"value":540},{"type":42,"tag":322,"props":696,"children":698},{"class":324,"line":697},21,[699],{"type":42,"tag":322,"props":700,"children":701},{},[702],{"type":48,"value":703},"### Validate before you run\n",{"type":42,"tag":322,"props":705,"children":707},{"class":324,"line":706},22,[708],{"type":42,"tag":322,"props":709,"children":710},{},[711],{"type":48,"value":712},"- Run `bruin validate \u003Cpath>` before `bruin run` - it catches YAML errors, missing connections, broken refs, and type mismatches without burning compute\n",{"type":42,"tag":322,"props":714,"children":716},{"class":324,"line":715},23,[717],{"type":42,"tag":322,"props":718,"children":719},{},[720],{"type":48,"value":721},"- If validation fails, read the error, fix the root cause at the source, then re-validate. Do not chain `run` attempts hoping they work\n",{"type":42,"tag":322,"props":723,"children":725},{"class":324,"line":724},24,[726],{"type":42,"tag":322,"props":727,"children":728},{},[729],{"type":48,"value":730},"- After running, do **spot checks across layers**: row counts, date min/max, null counts, and a handful of sample rows at each tier (raw → staging → marts). A pipeline that \"succeeded\" can still have silently wrong data\n",{"type":42,"tag":322,"props":732,"children":734},{"class":324,"line":733},25,[735],{"type":42,"tag":322,"props":736,"children":737},{"emptyLinePlaceholder":537},[738],{"type":48,"value":540},{"type":42,"tag":322,"props":740,"children":742},{"class":324,"line":741},26,[743],{"type":42,"tag":322,"props":744,"children":745},{},[746],{"type":48,"value":747},"### Document as you add\n",{"type":42,"tag":322,"props":749,"children":751},{"class":324,"line":750},27,[752],{"type":42,"tag":322,"props":753,"children":754},{},[755],{"type":48,"value":756},"- Every asset: **top-level description** explaining what it produces and why\n",{"type":42,"tag":322,"props":758,"children":760},{"class":324,"line":759},28,[761],{"type":42,"tag":322,"props":762,"children":763},{},[764],{"type":48,"value":765},"- Every meaningful column: **column-level description**. Don't let `cost_micros`, `status_code`, or `price_adj` go undocumented\n",{"type":42,"tag":322,"props":767,"children":769},{"class":324,"line":768},29,[770],{"type":42,"tag":322,"props":771,"children":772},{},[773],{"type":48,"value":774},"- Add **tags** to group assets (e.g. `tier:raw`, `domain:finance`, `owner:analyst`)\n",{"type":42,"tag":322,"props":776,"children":778},{"class":324,"line":777},30,[779],{"type":42,"tag":322,"props":780,"children":781},{},[782],{"type":48,"value":783},"- Add **quality checks** (`not_null`, `unique`, `accepted_values`, `positive`) on columns where the invariant matters\n",{"type":42,"tag":322,"props":785,"children":787},{"class":324,"line":786},31,[788],{"type":42,"tag":322,"props":789,"children":790},{},[791],{"type":48,"value":792},"- Add **custom checks** (SQL-backed assertions) for business rules that can't be expressed at the column level\n",{"type":42,"tag":322,"props":794,"children":796},{"class":324,"line":795},32,[797],{"type":42,"tag":322,"props":798,"children":799},{},[800],{"type":48,"value":801},"- Add **metadata** (owner, source system, refresh cadence, SLA) so future-you and future-agents have context\n",{"type":42,"tag":322,"props":803,"children":805},{"class":324,"line":804},33,[806],{"type":42,"tag":322,"props":807,"children":808},{"emptyLinePlaceholder":537},[809],{"type":48,"value":540},{"type":42,"tag":322,"props":811,"children":813},{"class":324,"line":812},34,[814],{"type":42,"tag":322,"props":815,"children":816},{},[817],{"type":48,"value":818},"### Keep this file current\n",{"type":42,"tag":322,"props":820,"children":822},{"class":324,"line":821},35,[823],{"type":42,"tag":322,"props":824,"children":825},{},[826],{"type":48,"value":827},"- When you learn a non-obvious fact about the data, a convention the user prefers, or a mistake worth avoiding - **append it to this file**. That's how the agent gets smarter across sessions\n",{"type":42,"tag":322,"props":829,"children":831},{"class":324,"line":830},36,[832],{"type":42,"tag":322,"props":833,"children":834},{"emptyLinePlaceholder":537},[835],{"type":48,"value":540},{"type":42,"tag":322,"props":837,"children":839},{"class":324,"line":838},37,[840],{"type":42,"tag":322,"props":841,"children":842},{},[843],{"type":48,"value":844},"### Naming and structure\n",{"type":42,"tag":322,"props":846,"children":848},{"class":324,"line":847},38,[849],{"type":42,"tag":322,"props":850,"children":851},{},[852],{"type":48,"value":853},"- Schemas: `raw.*` for ingestion output, `staging.*` for cleaned/typed, `marts.*` for business-ready tables\n",{"type":42,"tag":322,"props":855,"children":857},{"class":324,"line":856},39,[858],{"type":42,"tag":322,"props":859,"children":860},{},[861],{"type":48,"value":862},"- Asset file names should match the table they produce (e.g. `raw.fmp_fundamentals` → `fmp_fundamentals.asset.yml`)\n",{"type":42,"tag":322,"props":864,"children":866},{"class":324,"line":865},40,[867],{"type":42,"tag":322,"props":868,"children":869},{},[870],{"type":48,"value":871},"- Keep SQL assets under `\u003Cpipeline>/assets/`, same folder as ingestr assets\n",{"type":42,"tag":322,"props":873,"children":875},{"class":324,"line":874},41,[876],{"type":42,"tag":322,"props":877,"children":878},{},[879],{"type":48,"value":880},"- SQL assets should be **idempotent** - re-running produces the same output\n",{"type":42,"tag":322,"props":882,"children":884},{"class":324,"line":883},42,[885],{"type":42,"tag":322,"props":886,"children":887},{"emptyLinePlaceholder":537},[888],{"type":48,"value":540},{"type":42,"tag":322,"props":890,"children":892},{"class":324,"line":891},43,[893],{"type":42,"tag":322,"props":894,"children":895},{},[896],{"type":48,"value":897},"### Safety\n",{"type":42,"tag":322,"props":899,"children":901},{"class":324,"line":900},44,[902],{"type":42,"tag":322,"props":903,"children":904},{},[905],{"type":48,"value":906},"- **Never commit `.bruin.yml`.** It holds secrets. It's git-ignored by default; verify before staging\n",{"type":42,"tag":322,"props":908,"children":910},{"class":324,"line":909},45,[911],{"type":42,"tag":322,"props":912,"children":913},{},[914],{"type":48,"value":915},"- **Never run `DROP`, `DELETE`, `TRUNCATE`, or `UPDATE`** on raw tables - they're the ingestion output and should be rebuilt via `bruin run`, not mutated\n",{"type":42,"tag":322,"props":917,"children":919},{"class":324,"line":918},46,[920],{"type":42,"tag":322,"props":921,"children":922},{},[923],{"type":48,"value":924},"- When I say \"reset\" or \"start over\", ask me exactly what to drop before dropping anything\n",{"type":42,"tag":322,"props":926,"children":928},{"class":324,"line":927},47,[929],{"type":42,"tag":322,"props":930,"children":931},{"emptyLinePlaceholder":537},[932],{"type":48,"value":540},{"type":42,"tag":322,"props":934,"children":936},{"class":324,"line":935},48,[937],{"type":42,"tag":322,"props":938,"children":939},{},[940],{"type":48,"value":941},"### Show your work\n",{"type":42,"tag":322,"props":943,"children":945},{"class":324,"line":944},49,[946],{"type":42,"tag":322,"props":947,"children":948},{},[949],{"type":48,"value":950},"- Before running a command that modifies files or data, show the plan and wait for approval\n",{"type":42,"tag":322,"props":952,"children":954},{"class":324,"line":953},50,[955],{"type":42,"tag":322,"props":956,"children":957},{},[958],{"type":48,"value":959},"- Print the SQL before executing it\n",{"type":42,"tag":322,"props":961,"children":963},{"class":324,"line":962},51,[964],{"type":42,"tag":322,"props":965,"children":966},{},[967],{"type":48,"value":968},"- When editing YAML, show the final file or a diff - not just \"done\"\n",{"type":42,"tag":51,"props":970,"children":971},{},[972,974,979,981,986,988,994],{"type":48,"value":973},"When the agent's done, you have two foundations in place: the project structure itself, and a root ",{"type":42,"tag":57,"props":975,"children":977},{"className":976},[],[978],{"type":48,"value":69},{"type":48,"value":980}," that will travel with the workspace and keep every future session consistent. In Step 4 you'll add a second, pipeline-specific ",{"type":42,"tag":57,"props":982,"children":984},{"className":983},[],[985],{"type":48,"value":69},{"type":48,"value":987}," inside the ",{"type":42,"tag":57,"props":989,"children":991},{"className":990},[],[992],{"type":48,"value":993},"stock-analyst-101/",{"type":48,"value":995}," folder for the finance-specific domain knowledge - keeping general Bruin rules at the workspace level and domain context scoped to the pipeline.",{"type":42,"tag":43,"props":997,"children":999},{"id":998},"what-just-happened",[1000],{"type":48,"value":1001},"What just happened",{"type":42,"tag":51,"props":1003,"children":1004},{},[1005,1007,1012],{"type":48,"value":1006},"You have a Bruin project with a working DuckDB connection and an ",{"type":42,"tag":57,"props":1008,"children":1010},{"className":1009},[],[1011],{"type":48,"value":69},{"type":48,"value":1013}," that tells the AI agent exactly how to behave inside this project. No data in it yet, but the plumbing and the playbook are both in place. Next step: plug in FMP, Yahoo Finance, and FRED as data sources and let Bruin pull real data into DuckDB.",{"type":42,"tag":1015,"props":1016,"children":1017},"style",{},[1018],{"type":48,"value":1019},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":7,"searchDepth":18,"depth":18,"links":1021},[1022,1023,1024,1025,1026,1028,1030],{"id":45,"depth":18,"text":49},{"id":74,"depth":18,"text":77},{"id":147,"depth":18,"text":150},{"id":248,"depth":18,"text":251},{"id":291,"depth":18,"text":1027},"Peek inside .bruin.yml",{"id":426,"depth":18,"text":1029},"Seed AGENTS.md with Bruin rules",{"id":998,"depth":18,"text":1001},"content:tutorials:stock-analyst-101:scaffold-template.md","content","tutorials/stock-analyst-101/scaffold-template.md","tutorials/stock-analyst-101/scaffold-template","md",{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"readingTime":11,"category":12,"tags":1037,"difficulty":17,"module":5,"step":18,"journeys":1038,"roles":1039,"learnMore":1040,"author":1044,"body":1045,"_type":519,"_id":1031,"_source":1032,"_file":1033,"_stem":1034,"_extension":1035},[14,15,16],[20],[22,23],[1041,1042,1043],{"label":26,"url":27},{"label":29,"url":30},{"label":32,"url":33},{"name":35,"role":36,"image":37},{"type":39,"children":1046,"toc":1816},[1047,1051,1067,1071,1075,1117,1121,1125,1129,1160,1164,1201,1205,1209,1217,1221,1234,1243,1253,1337,1341,1351,1366,1370,1776,1798,1802,1812],{"type":42,"tag":43,"props":1048,"children":1049},{"id":45},[1050],{"type":48,"value":49},{"type":42,"tag":51,"props":1052,"children":1053},{},[1054,1055,1060,1061,1066],{"type":48,"value":55},{"type":42,"tag":57,"props":1056,"children":1058},{"className":1057},[],[1059],{"type":48,"value":5},{"type":48,"value":63},{"type":42,"tag":57,"props":1062,"children":1064},{"className":1063},[],[1065],{"type":48,"value":69},{"type":48,"value":71},{"type":42,"tag":43,"props":1068,"children":1069},{"id":74},[1070],{"type":48,"value":77},{"type":42,"tag":51,"props":1072,"children":1073},{},[1074],{"type":48,"value":82},{"type":42,"tag":84,"props":1076,"children":1077},{},[1078,1093,1102],{"type":42,"tag":88,"props":1079,"children":1080},{},[1081,1082,1086,1087,1092],{"type":48,"value":92},{"type":42,"tag":94,"props":1083,"children":1084},{},[1085],{"type":48,"value":98},{"type":48,"value":100},{"type":42,"tag":57,"props":1088,"children":1090},{"className":1089},[],[1091],{"type":48,"value":106},{"type":48,"value":108},{"type":42,"tag":88,"props":1094,"children":1095},{},[1096,1097,1101],{"type":48,"value":113},{"type":42,"tag":94,"props":1098,"children":1099},{},[1100],{"type":48,"value":118},{"type":48,"value":120},{"type":42,"tag":88,"props":1103,"children":1104},{},[1105,1106,1110,1111,1116],{"type":48,"value":92},{"type":42,"tag":94,"props":1107,"children":1108},{},[1109],{"type":48,"value":129},{"type":48,"value":131},{"type":42,"tag":57,"props":1112,"children":1114},{"className":1113},[],[1115],{"type":48,"value":137},{"type":48,"value":139},{"type":42,"tag":51,"props":1118,"children":1119},{},[1120],{"type":48,"value":144},{"type":42,"tag":43,"props":1122,"children":1123},{"id":147},[1124],{"type":48,"value":150},{"type":42,"tag":51,"props":1126,"children":1127},{},[1128],{"type":48,"value":155},{"type":42,"tag":157,"props":1130,"children":1131},{},[1132],{"type":42,"tag":51,"props":1133,"children":1134},{},[1135,1136,1141,1142,1147,1148,1153,1154,1159],{"type":48,"value":164},{"type":42,"tag":57,"props":1137,"children":1139},{"className":1138},[],[1140],{"type":48,"value":170},{"type":48,"value":172},{"type":42,"tag":57,"props":1143,"children":1145},{"className":1144},[],[1146],{"type":48,"value":178},{"type":48,"value":180},{"type":42,"tag":57,"props":1149,"children":1151},{"className":1150},[],[1152],{"type":48,"value":186},{"type":48,"value":188},{"type":42,"tag":57,"props":1155,"children":1157},{"className":1156},[],[1158],{"type":48,"value":194},{"type":48,"value":196},{"type":42,"tag":51,"props":1161,"children":1162},{},[1163],{"type":48,"value":201},{"type":42,"tag":203,"props":1165,"children":1166},{},[1167,1176,1197],{"type":42,"tag":88,"props":1168,"children":1169},{},[1170,1171],{"type":48,"value":210},{"type":42,"tag":57,"props":1172,"children":1174},{"className":1173},[],[1175],{"type":48,"value":170},{"type":42,"tag":88,"props":1177,"children":1178},{},[1179,1180,1185,1186,1191,1192],{"type":48,"value":220},{"type":42,"tag":57,"props":1181,"children":1183},{"className":1182},[],[1184],{"type":48,"value":106},{"type":48,"value":227},{"type":42,"tag":57,"props":1187,"children":1189},{"className":1188},[],[1190],{"type":48,"value":233},{"type":48,"value":235},{"type":42,"tag":57,"props":1193,"children":1195},{"className":1194},[],[1196],{"type":48,"value":186},{"type":42,"tag":88,"props":1198,"children":1199},{},[1200],{"type":48,"value":245},{"type":42,"tag":43,"props":1202,"children":1203},{"id":248},[1204],{"type":48,"value":251},{"type":42,"tag":51,"props":1206,"children":1207},{},[1208],{"type":48,"value":256},{"type":42,"tag":258,"props":1210,"children":1212},{"className":1211,"code":262,"language":48},[261],[1213],{"type":42,"tag":57,"props":1214,"children":1215},{"__ignoreMap":7},[1216],{"type":48,"value":262},{"type":42,"tag":51,"props":1218,"children":1219},{},[1220],{"type":48,"value":272},{"type":42,"tag":157,"props":1222,"children":1223},{},[1224],{"type":42,"tag":51,"props":1225,"children":1226},{},[1227,1228,1233],{"type":48,"value":280},{"type":42,"tag":57,"props":1229,"children":1231},{"className":1230},[],[1232],{"type":48,"value":286},{"type":48,"value":288},{"type":42,"tag":43,"props":1235,"children":1236},{"id":291},[1237,1238],{"type":48,"value":294},{"type":42,"tag":57,"props":1239,"children":1241},{"className":1240},[],[1242],{"type":48,"value":106},{"type":42,"tag":51,"props":1244,"children":1245},{},[1246,1247,1252],{"type":48,"value":304},{"type":42,"tag":57,"props":1248,"children":1250},{"className":1249},[],[1251],{"type":48,"value":106},{"type":48,"value":311},{"type":42,"tag":258,"props":1254,"children":1255},{"className":314,"code":315,"language":316,"meta":7,"style":7},[1256],{"type":42,"tag":57,"props":1257,"children":1258},{"__ignoreMap":7},[1259,1270,1281,1292,1303,1322],{"type":42,"tag":322,"props":1260,"children":1261},{"class":324,"line":325},[1262,1266],{"type":42,"tag":322,"props":1263,"children":1264},{"style":329},[1265],{"type":48,"value":332},{"type":42,"tag":322,"props":1267,"children":1268},{"style":335},[1269],{"type":48,"value":338},{"type":42,"tag":322,"props":1271,"children":1272},{"class":324,"line":18},[1273,1277],{"type":42,"tag":322,"props":1274,"children":1275},{"style":329},[1276],{"type":48,"value":346},{"type":42,"tag":322,"props":1278,"children":1279},{"style":335},[1280],{"type":48,"value":338},{"type":42,"tag":322,"props":1282,"children":1283},{"class":324,"line":353},[1284,1288],{"type":42,"tag":322,"props":1285,"children":1286},{"style":329},[1287],{"type":48,"value":359},{"type":42,"tag":322,"props":1289,"children":1290},{"style":335},[1291],{"type":48,"value":338},{"type":42,"tag":322,"props":1293,"children":1294},{"class":324,"line":366},[1295,1299],{"type":42,"tag":322,"props":1296,"children":1297},{"style":329},[1298],{"type":48,"value":372},{"type":42,"tag":322,"props":1300,"children":1301},{"style":335},[1302],{"type":48,"value":338},{"type":42,"tag":322,"props":1304,"children":1305},{"class":324,"line":11},[1306,1310,1314,1318],{"type":42,"tag":322,"props":1307,"children":1308},{"style":335},[1309],{"type":48,"value":384},{"type":42,"tag":322,"props":1311,"children":1312},{"style":329},[1313],{"type":48,"value":389},{"type":42,"tag":322,"props":1315,"children":1316},{"style":335},[1317],{"type":48,"value":394},{"type":42,"tag":322,"props":1319,"children":1320},{"style":397},[1321],{"type":48,"value":400},{"type":42,"tag":322,"props":1323,"children":1324},{"class":324,"line":403},[1325,1329,1333],{"type":42,"tag":322,"props":1326,"children":1327},{"style":329},[1328],{"type":48,"value":409},{"type":42,"tag":322,"props":1330,"children":1331},{"style":335},[1332],{"type":48,"value":394},{"type":42,"tag":322,"props":1334,"children":1335},{"style":397},[1336],{"type":48,"value":418},{"type":42,"tag":51,"props":1338,"children":1339},{},[1340],{"type":48,"value":423},{"type":42,"tag":43,"props":1342,"children":1343},{"id":426},[1344,1345,1350],{"type":48,"value":429},{"type":42,"tag":57,"props":1346,"children":1348},{"className":1347},[],[1349],{"type":48,"value":69},{"type":48,"value":436},{"type":42,"tag":51,"props":1352,"children":1353},{},[1354,1355,1360,1361,1365],{"type":48,"value":441},{"type":42,"tag":57,"props":1356,"children":1358},{"className":1357},[],[1359],{"type":48,"value":69},{"type":48,"value":448},{"type":42,"tag":450,"props":1362,"children":1363},{},[1364],{"type":48,"value":454},{"type":48,"value":456},{"type":42,"tag":51,"props":1367,"children":1368},{},[1369],{"type":48,"value":461},{"type":42,"tag":157,"props":1371,"children":1372},{},[1373,1413],{"type":42,"tag":51,"props":1374,"children":1375},{},[1376,1377,1382,1383,1388,1389,1394,1395,1400,1401,1406,1407,1412],{"type":48,"value":469},{"type":42,"tag":57,"props":1378,"children":1380},{"className":1379},[],[1381],{"type":48,"value":69},{"type":48,"value":476},{"type":42,"tag":57,"props":1384,"children":1386},{"className":1385},[],[1387],{"type":48,"value":106},{"type":48,"value":483},{"type":42,"tag":57,"props":1390,"children":1392},{"className":1391},[],[1393],{"type":48,"value":489},{"type":48,"value":491},{"type":42,"tag":57,"props":1396,"children":1398},{"className":1397},[],[1399],{"type":48,"value":497},{"type":48,"value":499},{"type":42,"tag":57,"props":1402,"children":1404},{"className":1403},[],[1405],{"type":48,"value":106},{"type":48,"value":506},{"type":42,"tag":57,"props":1408,"children":1410},{"className":1409},[],[1411],{"type":48,"value":512},{"type":48,"value":514},{"type":42,"tag":258,"props":1414,"children":1415},{"className":517,"code":518,"language":519,"meta":7,"style":7},[1416],{"type":42,"tag":57,"props":1417,"children":1418},{"__ignoreMap":7},[1419,1426,1433,1440,1447,1454,1461,1468,1475,1482,1489,1496,1503,1510,1517,1524,1531,1538,1545,1552,1559,1566,1573,1580,1587,1594,1601,1608,1615,1622,1629,1636,1643,1650,1657,1664,1671,1678,1685,1692,1699,1706,1713,1720,1727,1734,1741,1748,1755,1762,1769],{"type":42,"tag":322,"props":1420,"children":1421},{"class":324,"line":325},[1422],{"type":42,"tag":322,"props":1423,"children":1424},{},[1425],{"type":48,"value":531},{"type":42,"tag":322,"props":1427,"children":1428},{"class":324,"line":18},[1429],{"type":42,"tag":322,"props":1430,"children":1431},{"emptyLinePlaceholder":537},[1432],{"type":48,"value":540},{"type":42,"tag":322,"props":1434,"children":1435},{"class":324,"line":353},[1436],{"type":42,"tag":322,"props":1437,"children":1438},{},[1439],{"type":48,"value":548},{"type":42,"tag":322,"props":1441,"children":1442},{"class":324,"line":366},[1443],{"type":42,"tag":322,"props":1444,"children":1445},{"emptyLinePlaceholder":537},[1446],{"type":48,"value":540},{"type":42,"tag":322,"props":1448,"children":1449},{"class":324,"line":11},[1450],{"type":42,"tag":322,"props":1451,"children":1452},{},[1453],{"type":48,"value":563},{"type":42,"tag":322,"props":1455,"children":1456},{"class":324,"line":403},[1457],{"type":42,"tag":322,"props":1458,"children":1459},{},[1460],{"type":48,"value":571},{"type":42,"tag":322,"props":1462,"children":1463},{"class":324,"line":574},[1464],{"type":42,"tag":322,"props":1465,"children":1466},{},[1467],{"type":48,"value":580},{"type":42,"tag":322,"props":1469,"children":1470},{"class":324,"line":583},[1471],{"type":42,"tag":322,"props":1472,"children":1473},{},[1474],{"type":48,"value":589},{"type":42,"tag":322,"props":1476,"children":1477},{"class":324,"line":592},[1478],{"type":42,"tag":322,"props":1479,"children":1480},{},[1481],{"type":48,"value":598},{"type":42,"tag":322,"props":1483,"children":1484},{"class":324,"line":601},[1485],{"type":42,"tag":322,"props":1486,"children":1487},{"emptyLinePlaceholder":537},[1488],{"type":48,"value":540},{"type":42,"tag":322,"props":1490,"children":1491},{"class":324,"line":609},[1492],{"type":42,"tag":322,"props":1493,"children":1494},{},[1495],{"type":48,"value":615},{"type":42,"tag":322,"props":1497,"children":1498},{"class":324,"line":618},[1499],{"type":42,"tag":322,"props":1500,"children":1501},{},[1502],{"type":48,"value":624},{"type":42,"tag":322,"props":1504,"children":1505},{"class":324,"line":627},[1506],{"type":42,"tag":322,"props":1507,"children":1508},{},[1509],{"type":48,"value":633},{"type":42,"tag":322,"props":1511,"children":1512},{"class":324,"line":636},[1513],{"type":42,"tag":322,"props":1514,"children":1515},{},[1516],{"type":48,"value":642},{"type":42,"tag":322,"props":1518,"children":1519},{"class":324,"line":645},[1520],{"type":42,"tag":322,"props":1521,"children":1522},{"emptyLinePlaceholder":537},[1523],{"type":48,"value":540},{"type":42,"tag":322,"props":1525,"children":1526},{"class":324,"line":653},[1527],{"type":42,"tag":322,"props":1528,"children":1529},{},[1530],{"type":48,"value":659},{"type":42,"tag":322,"props":1532,"children":1533},{"class":324,"line":662},[1534],{"type":42,"tag":322,"props":1535,"children":1536},{},[1537],{"type":48,"value":668},{"type":42,"tag":322,"props":1539,"children":1540},{"class":324,"line":671},[1541],{"type":42,"tag":322,"props":1542,"children":1543},{},[1544],{"type":48,"value":677},{"type":42,"tag":322,"props":1546,"children":1547},{"class":324,"line":680},[1548],{"type":42,"tag":322,"props":1549,"children":1550},{},[1551],{"type":48,"value":686},{"type":42,"tag":322,"props":1553,"children":1554},{"class":324,"line":689},[1555],{"type":42,"tag":322,"props":1556,"children":1557},{"emptyLinePlaceholder":537},[1558],{"type":48,"value":540},{"type":42,"tag":322,"props":1560,"children":1561},{"class":324,"line":697},[1562],{"type":42,"tag":322,"props":1563,"children":1564},{},[1565],{"type":48,"value":703},{"type":42,"tag":322,"props":1567,"children":1568},{"class":324,"line":706},[1569],{"type":42,"tag":322,"props":1570,"children":1571},{},[1572],{"type":48,"value":712},{"type":42,"tag":322,"props":1574,"children":1575},{"class":324,"line":715},[1576],{"type":42,"tag":322,"props":1577,"children":1578},{},[1579],{"type":48,"value":721},{"type":42,"tag":322,"props":1581,"children":1582},{"class":324,"line":724},[1583],{"type":42,"tag":322,"props":1584,"children":1585},{},[1586],{"type":48,"value":730},{"type":42,"tag":322,"props":1588,"children":1589},{"class":324,"line":733},[1590],{"type":42,"tag":322,"props":1591,"children":1592},{"emptyLinePlaceholder":537},[1593],{"type":48,"value":540},{"type":42,"tag":322,"props":1595,"children":1596},{"class":324,"line":741},[1597],{"type":42,"tag":322,"props":1598,"children":1599},{},[1600],{"type":48,"value":747},{"type":42,"tag":322,"props":1602,"children":1603},{"class":324,"line":750},[1604],{"type":42,"tag":322,"props":1605,"children":1606},{},[1607],{"type":48,"value":756},{"type":42,"tag":322,"props":1609,"children":1610},{"class":324,"line":759},[1611],{"type":42,"tag":322,"props":1612,"children":1613},{},[1614],{"type":48,"value":765},{"type":42,"tag":322,"props":1616,"children":1617},{"class":324,"line":768},[1618],{"type":42,"tag":322,"props":1619,"children":1620},{},[1621],{"type":48,"value":774},{"type":42,"tag":322,"props":1623,"children":1624},{"class":324,"line":777},[1625],{"type":42,"tag":322,"props":1626,"children":1627},{},[1628],{"type":48,"value":783},{"type":42,"tag":322,"props":1630,"children":1631},{"class":324,"line":786},[1632],{"type":42,"tag":322,"props":1633,"children":1634},{},[1635],{"type":48,"value":792},{"type":42,"tag":322,"props":1637,"children":1638},{"class":324,"line":795},[1639],{"type":42,"tag":322,"props":1640,"children":1641},{},[1642],{"type":48,"value":801},{"type":42,"tag":322,"props":1644,"children":1645},{"class":324,"line":804},[1646],{"type":42,"tag":322,"props":1647,"children":1648},{"emptyLinePlaceholder":537},[1649],{"type":48,"value":540},{"type":42,"tag":322,"props":1651,"children":1652},{"class":324,"line":812},[1653],{"type":42,"tag":322,"props":1654,"children":1655},{},[1656],{"type":48,"value":818},{"type":42,"tag":322,"props":1658,"children":1659},{"class":324,"line":821},[1660],{"type":42,"tag":322,"props":1661,"children":1662},{},[1663],{"type":48,"value":827},{"type":42,"tag":322,"props":1665,"children":1666},{"class":324,"line":830},[1667],{"type":42,"tag":322,"props":1668,"children":1669},{"emptyLinePlaceholder":537},[1670],{"type":48,"value":540},{"type":42,"tag":322,"props":1672,"children":1673},{"class":324,"line":838},[1674],{"type":42,"tag":322,"props":1675,"children":1676},{},[1677],{"type":48,"value":844},{"type":42,"tag":322,"props":1679,"children":1680},{"class":324,"line":847},[1681],{"type":42,"tag":322,"props":1682,"children":1683},{},[1684],{"type":48,"value":853},{"type":42,"tag":322,"props":1686,"children":1687},{"class":324,"line":856},[1688],{"type":42,"tag":322,"props":1689,"children":1690},{},[1691],{"type":48,"value":862},{"type":42,"tag":322,"props":1693,"children":1694},{"class":324,"line":865},[1695],{"type":42,"tag":322,"props":1696,"children":1697},{},[1698],{"type":48,"value":871},{"type":42,"tag":322,"props":1700,"children":1701},{"class":324,"line":874},[1702],{"type":42,"tag":322,"props":1703,"children":1704},{},[1705],{"type":48,"value":880},{"type":42,"tag":322,"props":1707,"children":1708},{"class":324,"line":883},[1709],{"type":42,"tag":322,"props":1710,"children":1711},{"emptyLinePlaceholder":537},[1712],{"type":48,"value":540},{"type":42,"tag":322,"props":1714,"children":1715},{"class":324,"line":891},[1716],{"type":42,"tag":322,"props":1717,"children":1718},{},[1719],{"type":48,"value":897},{"type":42,"tag":322,"props":1721,"children":1722},{"class":324,"line":900},[1723],{"type":42,"tag":322,"props":1724,"children":1725},{},[1726],{"type":48,"value":906},{"type":42,"tag":322,"props":1728,"children":1729},{"class":324,"line":909},[1730],{"type":42,"tag":322,"props":1731,"children":1732},{},[1733],{"type":48,"value":915},{"type":42,"tag":322,"props":1735,"children":1736},{"class":324,"line":918},[1737],{"type":42,"tag":322,"props":1738,"children":1739},{},[1740],{"type":48,"value":924},{"type":42,"tag":322,"props":1742,"children":1743},{"class":324,"line":927},[1744],{"type":42,"tag":322,"props":1745,"children":1746},{"emptyLinePlaceholder":537},[1747],{"type":48,"value":540},{"type":42,"tag":322,"props":1749,"children":1750},{"class":324,"line":935},[1751],{"type":42,"tag":322,"props":1752,"children":1753},{},[1754],{"type":48,"value":941},{"type":42,"tag":322,"props":1756,"children":1757},{"class":324,"line":944},[1758],{"type":42,"tag":322,"props":1759,"children":1760},{},[1761],{"type":48,"value":950},{"type":42,"tag":322,"props":1763,"children":1764},{"class":324,"line":953},[1765],{"type":42,"tag":322,"props":1766,"children":1767},{},[1768],{"type":48,"value":959},{"type":42,"tag":322,"props":1770,"children":1771},{"class":324,"line":962},[1772],{"type":42,"tag":322,"props":1773,"children":1774},{},[1775],{"type":48,"value":968},{"type":42,"tag":51,"props":1777,"children":1778},{},[1779,1780,1785,1786,1791,1792,1797],{"type":48,"value":973},{"type":42,"tag":57,"props":1781,"children":1783},{"className":1782},[],[1784],{"type":48,"value":69},{"type":48,"value":980},{"type":42,"tag":57,"props":1787,"children":1789},{"className":1788},[],[1790],{"type":48,"value":69},{"type":48,"value":987},{"type":42,"tag":57,"props":1793,"children":1795},{"className":1794},[],[1796],{"type":48,"value":993},{"type":48,"value":995},{"type":42,"tag":43,"props":1799,"children":1800},{"id":998},[1801],{"type":48,"value":1001},{"type":42,"tag":51,"props":1803,"children":1804},{},[1805,1806,1811],{"type":48,"value":1006},{"type":42,"tag":57,"props":1807,"children":1809},{"className":1808},[],[1810],{"type":48,"value":69},{"type":48,"value":1013},{"type":42,"tag":1015,"props":1813,"children":1814},{},[1815],{"type":48,"value":1019},{"title":7,"searchDepth":18,"depth":18,"links":1817},[1818,1819,1820,1821,1822,1823,1824],{"id":45,"depth":18,"text":49},{"id":74,"depth":18,"text":77},{"id":147,"depth":18,"text":150},{"id":248,"depth":18,"text":251},{"id":291,"depth":18,"text":1027},{"id":426,"depth":18,"text":1029},{"id":998,"depth":18,"text":1001},[1826,2388,3177,4136,5077,6188],{"_path":1827,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1828,"description":1829,"date":10,"readingTime":583,"category":12,"tags":1830,"difficulty":17,"module":5,"step":325,"journeys":1832,"roles":1833,"learnMore":1834,"author":1841,"body":1842,"_type":519,"_id":2385,"_source":1032,"_file":2386,"_stem":2387,"_extension":1035},"/tutorials/stock-analyst-101/setup-workspace","Set Up Your Workspace","Install your AI coding tool, then have it install Bruin CLI and wire up MCP for you. Every step from here on is a plain-English prompt.",[14,15,1831,16],"MCP",[20],[22,23],[1835,1838],{"label":1836,"url":1837},"Bruin CLI installation","https://getbruin.com/docs/bruin/getting-started/introduction/installation.html",{"label":1839,"url":1840},"Bruin MCP setup","https://getbruin.com/docs/bruin/getting-started/bruin-mcp.html",{"name":35,"role":36,"image":37},{"type":39,"children":1843,"toc":2376},[1844,1848,1866,1871,1875,1880,1886,1891,2009,2015,2020,2052,2057,2078,2084,2089,2332,2338,2343,2351,2363,2367,2372],{"type":42,"tag":43,"props":1845,"children":1846},{"id":45},[1847],{"type":48,"value":49},{"type":42,"tag":203,"props":1849,"children":1850},{},[1851,1856,1861],{"type":42,"tag":88,"props":1852,"children":1853},{},[1854],{"type":48,"value":1855},"Install an AI coding tool (Claude Code, Cursor, or Codex) - the only thing you install yourself",{"type":42,"tag":88,"props":1857,"children":1858},{},[1859],{"type":48,"value":1860},"Have the agent install Bruin CLI on your laptop for you",{"type":42,"tag":88,"props":1862,"children":1863},{},[1864],{"type":48,"value":1865},"Wire the agent to Bruin via MCP so it can run Bruin commands on your behalf",{"type":42,"tag":51,"props":1867,"children":1868},{},[1869],{"type":48,"value":1870},"After this step you stop running terminal commands. You prompt the agent in plain English and it does the running.",{"type":42,"tag":43,"props":1872,"children":1873},{"id":74},[1874],{"type":48,"value":77},{"type":42,"tag":51,"props":1876,"children":1877},{},[1878],{"type":48,"value":1879},"Every step after this is a plain-English prompt - \"pull the last 90 days of prices for these tickers\", \"build a staging view\", \"which sectors have the best free cash flow growth?\". The AI agent is the one typing commands, editing files, and running SQL. You're the analyst telling it what you want. This step installs the agent and gives it the keys to the workshop.",{"type":42,"tag":43,"props":1881,"children":1883},{"id":1882},"_1-install-your-ai-coding-tool",[1884],{"type":48,"value":1885},"1. Install your AI coding tool",{"type":42,"tag":51,"props":1887,"children":1888},{},[1889],{"type":48,"value":1890},"Pick one - any of these works. Claude Code is the fastest to get running.",{"type":42,"tag":1892,"props":1893,"children":1895},"variant-tabs",{":variants":1894},"[{\"id\":\"claude-code\",\"label\":\"Claude Code\"},{\"id\":\"cursor\",\"label\":\"Cursor\"},{\"id\":\"codex\",\"label\":\"Codex\"}]",[1896,1964,1987],{"type":42,"tag":1897,"props":1898,"children":1899},"template",{"v-slot:claude-code":7},[1900,1907,1923,1951],{"type":42,"tag":1901,"props":1902,"children":1904},"h3",{"id":1903},"claude-code",[1905],{"type":48,"value":1906},"Claude Code",{"type":42,"tag":51,"props":1908,"children":1909},{},[1910,1912,1921],{"type":48,"value":1911},"Follow the ",{"type":42,"tag":1913,"props":1914,"children":1918},"a",{"href":1915,"rel":1916},"https://docs.anthropic.com/en/docs/claude-code/overview",[1917],"nofollow",[1919],{"type":48,"value":1920},"Claude Code installation guide",{"type":48,"value":1922},". On Mac it's one command:",{"type":42,"tag":258,"props":1924,"children":1928},{"className":1925,"code":1926,"language":1927,"meta":7,"style":7},"language-bash shiki shiki-themes github-dark","brew install claude\n","bash",[1929],{"type":42,"tag":57,"props":1930,"children":1931},{"__ignoreMap":7},[1932],{"type":42,"tag":322,"props":1933,"children":1934},{"class":324,"line":325},[1935,1941,1946],{"type":42,"tag":322,"props":1936,"children":1938},{"style":1937},"--shiki-default:#B392F0",[1939],{"type":48,"value":1940},"brew",{"type":42,"tag":322,"props":1942,"children":1943},{"style":397},[1944],{"type":48,"value":1945}," install",{"type":42,"tag":322,"props":1947,"children":1948},{"style":397},[1949],{"type":48,"value":1950}," claude\n",{"type":42,"tag":51,"props":1952,"children":1953},{},[1954,1956,1962],{"type":48,"value":1955},"Sign in once (",{"type":42,"tag":57,"props":1957,"children":1959},{"className":1958},[],[1960],{"type":48,"value":1961},"claude",{"type":48,"value":1963}," - it opens a browser) and you're ready.",{"type":42,"tag":1897,"props":1965,"children":1966},{"v-slot:cursor":7},[1967,1973],{"type":42,"tag":1901,"props":1968,"children":1970},{"id":1969},"cursor",[1971],{"type":48,"value":1972},"Cursor",{"type":42,"tag":51,"props":1974,"children":1975},{},[1976,1978,1985],{"type":48,"value":1977},"Download Cursor from ",{"type":42,"tag":1913,"props":1979,"children":1982},{"href":1980,"rel":1981},"https://cursor.com/",[1917],[1983],{"type":48,"value":1984},"cursor.com",{"type":48,"value":1986}," and sign in. Cursor is a full IDE - you'll open a folder in it for the rest of the tutorial.",{"type":42,"tag":1897,"props":1988,"children":1989},{"v-slot:codex":7},[1990,1996],{"type":42,"tag":1901,"props":1991,"children":1993},{"id":1992},"codex",[1994],{"type":48,"value":1995},"Codex",{"type":42,"tag":51,"props":1997,"children":1998},{},[1999,2000,2007],{"type":48,"value":1911},{"type":42,"tag":1913,"props":2001,"children":2004},{"href":2002,"rel":2003},"https://openai.com/index/introducing-codex/",[1917],[2005],{"type":48,"value":2006},"Codex installation instructions",{"type":48,"value":2008},". Sign in with your OpenAI account.",{"type":42,"tag":43,"props":2010,"children":2012},{"id":2011},"_2-have-the-agent-install-bruin-cli",[2013],{"type":48,"value":2014},"2. Have the agent install Bruin CLI",{"type":42,"tag":51,"props":2016,"children":2017},{},[2018],{"type":48,"value":2019},"Open your AI tool in any folder you'd like to use as your workspace, and prompt:",{"type":42,"tag":157,"props":2021,"children":2022},{},[2023],{"type":42,"tag":51,"props":2024,"children":2025},{},[2026,2028,2034,2036,2042,2044,2050],{"type":48,"value":2027},"Install the Bruin CLI on this machine by running ",{"type":42,"tag":57,"props":2029,"children":2031},{"className":2030},[],[2032],{"type":48,"value":2033},"curl -LsSf https://getbruin.com/install/cli | sh",{"type":48,"value":2035},", then verify it worked with ",{"type":42,"tag":57,"props":2037,"children":2039},{"className":2038},[],[2040],{"type":48,"value":2041},"bruin --version",{"type":48,"value":2043},". If ",{"type":42,"tag":57,"props":2045,"children":2047},{"className":2046},[],[2048],{"type":48,"value":2049},"bruin",{"type":48,"value":2051}," isn't on my PATH after install, tell me what to add or which terminal to open.",{"type":42,"tag":51,"props":2053,"children":2054},{},[2055],{"type":48,"value":2056},"The agent will ask for permission to run a shell command - approve it. (You'll see this prompt a lot in the steps that follow; you're authorizing the agent to do the work for you.) When it finishes, the agent should print back a Bruin version number.",{"type":42,"tag":2058,"props":2059,"children":2060},"blockquote",{},[2061],{"type":42,"tag":51,"props":2062,"children":2063},{},[2064,2069,2071,2076],{"type":42,"tag":94,"props":2065,"children":2066},{},[2067],{"type":48,"value":2068},"If your AI tool can't run terminal commands",{"type":48,"value":2070},", paste the install command into any terminal yourself: ",{"type":42,"tag":57,"props":2072,"children":2074},{"className":2073},[],[2075],{"type":48,"value":2033},{"type":48,"value":2077},". The rest of the tutorial works the same.",{"type":42,"tag":43,"props":2079,"children":2081},{"id":2080},"_3-add-bruin-as-an-mcp-server",[2082],{"type":48,"value":2083},"3. Add Bruin as an MCP server",{"type":42,"tag":51,"props":2085,"children":2086},{},[2087],{"type":48,"value":2088},"MCP (Model Context Protocol) is the bridge that lets your AI tool call Bruin commands directly. Once it's wired up, the agent can ingest, query, validate - all of it - through prompts.",{"type":42,"tag":1892,"props":2090,"children":2091},{":variants":1894},[2092,2130,2261],{"type":42,"tag":1897,"props":2093,"children":2094},{"v-slot:claude-code":7},[2095,2100,2104,2120],{"type":42,"tag":1901,"props":2096,"children":2098},{"id":2097},"claude-code-1",[2099],{"type":48,"value":1906},{"type":42,"tag":51,"props":2101,"children":2102},{},[2103],{"type":48,"value":461},{"type":42,"tag":157,"props":2105,"children":2106},{},[2107],{"type":42,"tag":51,"props":2108,"children":2109},{},[2110,2112,2118],{"type":48,"value":2111},"Register Bruin as an MCP server by running ",{"type":42,"tag":57,"props":2113,"children":2115},{"className":2114},[],[2116],{"type":48,"value":2117},"claude mcp add bruin -- bruin mcp",{"type":48,"value":2119},". Then remind me to restart Claude Code so the change takes effect.",{"type":42,"tag":51,"props":2121,"children":2122},{},[2123,2128],{"type":42,"tag":94,"props":2124,"children":2125},{},[2126],{"type":48,"value":2127},"Important:",{"type":48,"value":2129}," close your current Claude Code session and start a new one before moving on.",{"type":42,"tag":1897,"props":2131,"children":2132},{"v-slot:cursor":7},[2133,2138,2143,2180,2253],{"type":42,"tag":1901,"props":2134,"children":2136},{"id":2135},"cursor-1",[2137],{"type":48,"value":1972},{"type":42,"tag":51,"props":2139,"children":2140},{},[2141],{"type":48,"value":2142},"Cursor's MCP setup is a UI step - the agent can't do this one for you:",{"type":42,"tag":203,"props":2144,"children":2145},{},[2146,2165,2175],{"type":42,"tag":88,"props":2147,"children":2148},{},[2149,2151,2156,2157,2163],{"type":48,"value":2150},"Open ",{"type":42,"tag":94,"props":2152,"children":2153},{},[2154],{"type":48,"value":2155},"Cursor Settings",{"type":48,"value":100},{"type":42,"tag":57,"props":2158,"children":2160},{"className":2159},[],[2161],{"type":48,"value":2162},"Cmd/Ctrl + ,",{"type":48,"value":2164},")",{"type":42,"tag":88,"props":2166,"children":2167},{},[2168,2170],{"type":48,"value":2169},"Go to ",{"type":42,"tag":94,"props":2171,"children":2172},{},[2173],{"type":48,"value":2174},"MCP & Integrations → Add Custom MCP",{"type":42,"tag":88,"props":2176,"children":2177},{},[2178],{"type":48,"value":2179},"Paste:",{"type":42,"tag":258,"props":2181,"children":2185},{"className":2182,"code":2183,"language":2184,"meta":7,"style":7},"language-json shiki shiki-themes github-dark","{\n  \"mcpServers\": {\n    \"bruin\": {\n      \"command\": \"bruin\",\n      \"args\": [\"mcp\"]\n    }\n  }\n}\n","json",[2186],{"type":42,"tag":57,"props":2187,"children":2188},{"__ignoreMap":7},[2189,2197,2205,2213,2221,2229,2237,2245],{"type":42,"tag":322,"props":2190,"children":2191},{"class":324,"line":325},[2192],{"type":42,"tag":322,"props":2193,"children":2194},{},[2195],{"type":48,"value":2196},"{\n",{"type":42,"tag":322,"props":2198,"children":2199},{"class":324,"line":18},[2200],{"type":42,"tag":322,"props":2201,"children":2202},{},[2203],{"type":48,"value":2204},"  \"mcpServers\": {\n",{"type":42,"tag":322,"props":2206,"children":2207},{"class":324,"line":353},[2208],{"type":42,"tag":322,"props":2209,"children":2210},{},[2211],{"type":48,"value":2212},"    \"bruin\": {\n",{"type":42,"tag":322,"props":2214,"children":2215},{"class":324,"line":366},[2216],{"type":42,"tag":322,"props":2217,"children":2218},{},[2219],{"type":48,"value":2220},"      \"command\": \"bruin\",\n",{"type":42,"tag":322,"props":2222,"children":2223},{"class":324,"line":11},[2224],{"type":42,"tag":322,"props":2225,"children":2226},{},[2227],{"type":48,"value":2228},"      \"args\": [\"mcp\"]\n",{"type":42,"tag":322,"props":2230,"children":2231},{"class":324,"line":403},[2232],{"type":42,"tag":322,"props":2233,"children":2234},{},[2235],{"type":48,"value":2236},"    }\n",{"type":42,"tag":322,"props":2238,"children":2239},{"class":324,"line":574},[2240],{"type":42,"tag":322,"props":2241,"children":2242},{},[2243],{"type":48,"value":2244},"  }\n",{"type":42,"tag":322,"props":2246,"children":2247},{"class":324,"line":583},[2248],{"type":42,"tag":322,"props":2249,"children":2250},{},[2251],{"type":48,"value":2252},"}\n",{"type":42,"tag":203,"props":2254,"children":2255},{"start":366},[2256],{"type":42,"tag":88,"props":2257,"children":2258},{},[2259],{"type":48,"value":2260},"Restart Cursor.",{"type":42,"tag":1897,"props":2262,"children":2263},{"v-slot:codex":7},[2264,2269,2273,2327],{"type":42,"tag":1901,"props":2265,"children":2267},{"id":2266},"codex-1",[2268],{"type":48,"value":1995},{"type":42,"tag":51,"props":2270,"children":2271},{},[2272],{"type":48,"value":461},{"type":42,"tag":157,"props":2274,"children":2275},{},[2276,2289,2322],{"type":42,"tag":51,"props":2277,"children":2278},{},[2279,2281,2287],{"type":48,"value":2280},"Add a Bruin MCP server entry to ",{"type":42,"tag":57,"props":2282,"children":2284},{"className":2283},[],[2285],{"type":48,"value":2286},"~/.codex/config.toml",{"type":48,"value":2288}," so I can call Bruin from this tool. The block should be:",{"type":42,"tag":258,"props":2290,"children":2294},{"className":2291,"code":2292,"language":2293,"meta":7,"style":7},"language-toml shiki shiki-themes github-dark","[mcp_servers.bruin]\ncommand = \"bruin\"\nargs = [\"mcp\"]\n","toml",[2295],{"type":42,"tag":57,"props":2296,"children":2297},{"__ignoreMap":7},[2298,2306,2314],{"type":42,"tag":322,"props":2299,"children":2300},{"class":324,"line":325},[2301],{"type":42,"tag":322,"props":2302,"children":2303},{},[2304],{"type":48,"value":2305},"[mcp_servers.bruin]\n",{"type":42,"tag":322,"props":2307,"children":2308},{"class":324,"line":18},[2309],{"type":42,"tag":322,"props":2310,"children":2311},{},[2312],{"type":48,"value":2313},"command = \"bruin\"\n",{"type":42,"tag":322,"props":2315,"children":2316},{"class":324,"line":353},[2317],{"type":42,"tag":322,"props":2318,"children":2319},{},[2320],{"type":48,"value":2321},"args = [\"mcp\"]\n",{"type":42,"tag":51,"props":2323,"children":2324},{},[2325],{"type":48,"value":2326},"Then remind me to restart Codex.",{"type":42,"tag":51,"props":2328,"children":2329},{},[2330],{"type":48,"value":2331},"After it confirms, restart Codex.",{"type":42,"tag":43,"props":2333,"children":2335},{"id":2334},"_4-verify-the-wiring",[2336],{"type":48,"value":2337},"4. Verify the wiring",{"type":42,"tag":51,"props":2339,"children":2340},{},[2341],{"type":48,"value":2342},"Open your AI tool and prompt:",{"type":42,"tag":157,"props":2344,"children":2345},{},[2346],{"type":42,"tag":51,"props":2347,"children":2348},{},[2349],{"type":48,"value":2350},"List the Bruin connections I have configured.",{"type":42,"tag":51,"props":2352,"children":2353},{},[2354,2356,2361],{"type":48,"value":2355},"The agent should call Bruin, get back an empty list (you haven't added any connections yet), and report that. ",{"type":42,"tag":94,"props":2357,"children":2358},{},[2359],{"type":48,"value":2360},"You want the agent to actually run the command",{"type":48,"value":2362}," - not just guess. If it replies with generic text like \"I don't know, can you check?\", MCP isn't wired. Go back and double-check the setup above.",{"type":42,"tag":43,"props":2364,"children":2365},{"id":998},[2366],{"type":48,"value":1001},{"type":42,"tag":51,"props":2368,"children":2369},{},[2370],{"type":48,"value":2371},"You have the full toolchain on your laptop: an AI brain (Claude/Cursor/Codex), a data engine (Bruin), and a bridge between them (MCP). From here on out, every step is \"tell the agent what you want, the agent runs the command.\" You won't open a terminal yourself again unless you want to.",{"type":42,"tag":1015,"props":2373,"children":2374},{},[2375],{"type":48,"value":1019},{"title":7,"searchDepth":18,"depth":18,"links":2377},[2378,2379,2380,2381,2382,2383,2384],{"id":45,"depth":18,"text":49},{"id":74,"depth":18,"text":77},{"id":1882,"depth":18,"text":1885},{"id":2011,"depth":18,"text":2014},{"id":2080,"depth":18,"text":2083},{"id":2334,"depth":18,"text":2337},{"id":998,"depth":18,"text":1001},"content:tutorials:stock-analyst-101:setup-workspace.md","tutorials/stock-analyst-101/setup-workspace.md","tutorials/stock-analyst-101/setup-workspace",{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"readingTime":11,"category":12,"tags":2389,"difficulty":17,"module":5,"step":18,"journeys":2390,"roles":2391,"learnMore":2392,"author":2396,"body":2397,"_type":519,"_id":1031,"_source":1032,"_file":1033,"_stem":1034,"_extension":1035},[14,15,16],[20],[22,23],[2393,2394,2395],{"label":26,"url":27},{"label":29,"url":30},{"label":32,"url":33},{"name":35,"role":36,"image":37},{"type":39,"children":2398,"toc":3168},[2399,2403,2419,2423,2427,2469,2473,2477,2481,2512,2516,2553,2557,2561,2569,2573,2586,2595,2605,2689,2693,2703,2718,2722,3128,3150,3154,3164],{"type":42,"tag":43,"props":2400,"children":2401},{"id":45},[2402],{"type":48,"value":49},{"type":42,"tag":51,"props":2404,"children":2405},{},[2406,2407,2412,2413,2418],{"type":48,"value":55},{"type":42,"tag":57,"props":2408,"children":2410},{"className":2409},[],[2411],{"type":48,"value":5},{"type":48,"value":63},{"type":42,"tag":57,"props":2414,"children":2416},{"className":2415},[],[2417],{"type":48,"value":69},{"type":48,"value":71},{"type":42,"tag":43,"props":2420,"children":2421},{"id":74},[2422],{"type":48,"value":77},{"type":42,"tag":51,"props":2424,"children":2425},{},[2426],{"type":48,"value":82},{"type":42,"tag":84,"props":2428,"children":2429},{},[2430,2445,2454],{"type":42,"tag":88,"props":2431,"children":2432},{},[2433,2434,2438,2439,2444],{"type":48,"value":92},{"type":42,"tag":94,"props":2435,"children":2436},{},[2437],{"type":48,"value":98},{"type":48,"value":100},{"type":42,"tag":57,"props":2440,"children":2442},{"className":2441},[],[2443],{"type":48,"value":106},{"type":48,"value":108},{"type":42,"tag":88,"props":2446,"children":2447},{},[2448,2449,2453],{"type":48,"value":113},{"type":42,"tag":94,"props":2450,"children":2451},{},[2452],{"type":48,"value":118},{"type":48,"value":120},{"type":42,"tag":88,"props":2455,"children":2456},{},[2457,2458,2462,2463,2468],{"type":48,"value":92},{"type":42,"tag":94,"props":2459,"children":2460},{},[2461],{"type":48,"value":129},{"type":48,"value":131},{"type":42,"tag":57,"props":2464,"children":2466},{"className":2465},[],[2467],{"type":48,"value":137},{"type":48,"value":139},{"type":42,"tag":51,"props":2470,"children":2471},{},[2472],{"type":48,"value":144},{"type":42,"tag":43,"props":2474,"children":2475},{"id":147},[2476],{"type":48,"value":150},{"type":42,"tag":51,"props":2478,"children":2479},{},[2480],{"type":48,"value":155},{"type":42,"tag":157,"props":2482,"children":2483},{},[2484],{"type":42,"tag":51,"props":2485,"children":2486},{},[2487,2488,2493,2494,2499,2500,2505,2506,2511],{"type":48,"value":164},{"type":42,"tag":57,"props":2489,"children":2491},{"className":2490},[],[2492],{"type":48,"value":170},{"type":48,"value":172},{"type":42,"tag":57,"props":2495,"children":2497},{"className":2496},[],[2498],{"type":48,"value":178},{"type":48,"value":180},{"type":42,"tag":57,"props":2501,"children":2503},{"className":2502},[],[2504],{"type":48,"value":186},{"type":48,"value":188},{"type":42,"tag":57,"props":2507,"children":2509},{"className":2508},[],[2510],{"type":48,"value":194},{"type":48,"value":196},{"type":42,"tag":51,"props":2513,"children":2514},{},[2515],{"type":48,"value":201},{"type":42,"tag":203,"props":2517,"children":2518},{},[2519,2528,2549],{"type":42,"tag":88,"props":2520,"children":2521},{},[2522,2523],{"type":48,"value":210},{"type":42,"tag":57,"props":2524,"children":2526},{"className":2525},[],[2527],{"type":48,"value":170},{"type":42,"tag":88,"props":2529,"children":2530},{},[2531,2532,2537,2538,2543,2544],{"type":48,"value":220},{"type":42,"tag":57,"props":2533,"children":2535},{"className":2534},[],[2536],{"type":48,"value":106},{"type":48,"value":227},{"type":42,"tag":57,"props":2539,"children":2541},{"className":2540},[],[2542],{"type":48,"value":233},{"type":48,"value":235},{"type":42,"tag":57,"props":2545,"children":2547},{"className":2546},[],[2548],{"type":48,"value":186},{"type":42,"tag":88,"props":2550,"children":2551},{},[2552],{"type":48,"value":245},{"type":42,"tag":43,"props":2554,"children":2555},{"id":248},[2556],{"type":48,"value":251},{"type":42,"tag":51,"props":2558,"children":2559},{},[2560],{"type":48,"value":256},{"type":42,"tag":258,"props":2562,"children":2564},{"className":2563,"code":262,"language":48},[261],[2565],{"type":42,"tag":57,"props":2566,"children":2567},{"__ignoreMap":7},[2568],{"type":48,"value":262},{"type":42,"tag":51,"props":2570,"children":2571},{},[2572],{"type":48,"value":272},{"type":42,"tag":157,"props":2574,"children":2575},{},[2576],{"type":42,"tag":51,"props":2577,"children":2578},{},[2579,2580,2585],{"type":48,"value":280},{"type":42,"tag":57,"props":2581,"children":2583},{"className":2582},[],[2584],{"type":48,"value":286},{"type":48,"value":288},{"type":42,"tag":43,"props":2587,"children":2588},{"id":291},[2589,2590],{"type":48,"value":294},{"type":42,"tag":57,"props":2591,"children":2593},{"className":2592},[],[2594],{"type":48,"value":106},{"type":42,"tag":51,"props":2596,"children":2597},{},[2598,2599,2604],{"type":48,"value":304},{"type":42,"tag":57,"props":2600,"children":2602},{"className":2601},[],[2603],{"type":48,"value":106},{"type":48,"value":311},{"type":42,"tag":258,"props":2606,"children":2607},{"className":314,"code":315,"language":316,"meta":7,"style":7},[2608],{"type":42,"tag":57,"props":2609,"children":2610},{"__ignoreMap":7},[2611,2622,2633,2644,2655,2674],{"type":42,"tag":322,"props":2612,"children":2613},{"class":324,"line":325},[2614,2618],{"type":42,"tag":322,"props":2615,"children":2616},{"style":329},[2617],{"type":48,"value":332},{"type":42,"tag":322,"props":2619,"children":2620},{"style":335},[2621],{"type":48,"value":338},{"type":42,"tag":322,"props":2623,"children":2624},{"class":324,"line":18},[2625,2629],{"type":42,"tag":322,"props":2626,"children":2627},{"style":329},[2628],{"type":48,"value":346},{"type":42,"tag":322,"props":2630,"children":2631},{"style":335},[2632],{"type":48,"value":338},{"type":42,"tag":322,"props":2634,"children":2635},{"class":324,"line":353},[2636,2640],{"type":42,"tag":322,"props":2637,"children":2638},{"style":329},[2639],{"type":48,"value":359},{"type":42,"tag":322,"props":2641,"children":2642},{"style":335},[2643],{"type":48,"value":338},{"type":42,"tag":322,"props":2645,"children":2646},{"class":324,"line":366},[2647,2651],{"type":42,"tag":322,"props":2648,"children":2649},{"style":329},[2650],{"type":48,"value":372},{"type":42,"tag":322,"props":2652,"children":2653},{"style":335},[2654],{"type":48,"value":338},{"type":42,"tag":322,"props":2656,"children":2657},{"class":324,"line":11},[2658,2662,2666,2670],{"type":42,"tag":322,"props":2659,"children":2660},{"style":335},[2661],{"type":48,"value":384},{"type":42,"tag":322,"props":2663,"children":2664},{"style":329},[2665],{"type":48,"value":389},{"type":42,"tag":322,"props":2667,"children":2668},{"style":335},[2669],{"type":48,"value":394},{"type":42,"tag":322,"props":2671,"children":2672},{"style":397},[2673],{"type":48,"value":400},{"type":42,"tag":322,"props":2675,"children":2676},{"class":324,"line":403},[2677,2681,2685],{"type":42,"tag":322,"props":2678,"children":2679},{"style":329},[2680],{"type":48,"value":409},{"type":42,"tag":322,"props":2682,"children":2683},{"style":335},[2684],{"type":48,"value":394},{"type":42,"tag":322,"props":2686,"children":2687},{"style":397},[2688],{"type":48,"value":418},{"type":42,"tag":51,"props":2690,"children":2691},{},[2692],{"type":48,"value":423},{"type":42,"tag":43,"props":2694,"children":2695},{"id":426},[2696,2697,2702],{"type":48,"value":429},{"type":42,"tag":57,"props":2698,"children":2700},{"className":2699},[],[2701],{"type":48,"value":69},{"type":48,"value":436},{"type":42,"tag":51,"props":2704,"children":2705},{},[2706,2707,2712,2713,2717],{"type":48,"value":441},{"type":42,"tag":57,"props":2708,"children":2710},{"className":2709},[],[2711],{"type":48,"value":69},{"type":48,"value":448},{"type":42,"tag":450,"props":2714,"children":2715},{},[2716],{"type":48,"value":454},{"type":48,"value":456},{"type":42,"tag":51,"props":2719,"children":2720},{},[2721],{"type":48,"value":461},{"type":42,"tag":157,"props":2723,"children":2724},{},[2725,2765],{"type":42,"tag":51,"props":2726,"children":2727},{},[2728,2729,2734,2735,2740,2741,2746,2747,2752,2753,2758,2759,2764],{"type":48,"value":469},{"type":42,"tag":57,"props":2730,"children":2732},{"className":2731},[],[2733],{"type":48,"value":69},{"type":48,"value":476},{"type":42,"tag":57,"props":2736,"children":2738},{"className":2737},[],[2739],{"type":48,"value":106},{"type":48,"value":483},{"type":42,"tag":57,"props":2742,"children":2744},{"className":2743},[],[2745],{"type":48,"value":489},{"type":48,"value":491},{"type":42,"tag":57,"props":2748,"children":2750},{"className":2749},[],[2751],{"type":48,"value":497},{"type":48,"value":499},{"type":42,"tag":57,"props":2754,"children":2756},{"className":2755},[],[2757],{"type":48,"value":106},{"type":48,"value":506},{"type":42,"tag":57,"props":2760,"children":2762},{"className":2761},[],[2763],{"type":48,"value":512},{"type":48,"value":514},{"type":42,"tag":258,"props":2766,"children":2767},{"className":517,"code":518,"language":519,"meta":7,"style":7},[2768],{"type":42,"tag":57,"props":2769,"children":2770},{"__ignoreMap":7},[2771,2778,2785,2792,2799,2806,2813,2820,2827,2834,2841,2848,2855,2862,2869,2876,2883,2890,2897,2904,2911,2918,2925,2932,2939,2946,2953,2960,2967,2974,2981,2988,2995,3002,3009,3016,3023,3030,3037,3044,3051,3058,3065,3072,3079,3086,3093,3100,3107,3114,3121],{"type":42,"tag":322,"props":2772,"children":2773},{"class":324,"line":325},[2774],{"type":42,"tag":322,"props":2775,"children":2776},{},[2777],{"type":48,"value":531},{"type":42,"tag":322,"props":2779,"children":2780},{"class":324,"line":18},[2781],{"type":42,"tag":322,"props":2782,"children":2783},{"emptyLinePlaceholder":537},[2784],{"type":48,"value":540},{"type":42,"tag":322,"props":2786,"children":2787},{"class":324,"line":353},[2788],{"type":42,"tag":322,"props":2789,"children":2790},{},[2791],{"type":48,"value":548},{"type":42,"tag":322,"props":2793,"children":2794},{"class":324,"line":366},[2795],{"type":42,"tag":322,"props":2796,"children":2797},{"emptyLinePlaceholder":537},[2798],{"type":48,"value":540},{"type":42,"tag":322,"props":2800,"children":2801},{"class":324,"line":11},[2802],{"type":42,"tag":322,"props":2803,"children":2804},{},[2805],{"type":48,"value":563},{"type":42,"tag":322,"props":2807,"children":2808},{"class":324,"line":403},[2809],{"type":42,"tag":322,"props":2810,"children":2811},{},[2812],{"type":48,"value":571},{"type":42,"tag":322,"props":2814,"children":2815},{"class":324,"line":574},[2816],{"type":42,"tag":322,"props":2817,"children":2818},{},[2819],{"type":48,"value":580},{"type":42,"tag":322,"props":2821,"children":2822},{"class":324,"line":583},[2823],{"type":42,"tag":322,"props":2824,"children":2825},{},[2826],{"type":48,"value":589},{"type":42,"tag":322,"props":2828,"children":2829},{"class":324,"line":592},[2830],{"type":42,"tag":322,"props":2831,"children":2832},{},[2833],{"type":48,"value":598},{"type":42,"tag":322,"props":2835,"children":2836},{"class":324,"line":601},[2837],{"type":42,"tag":322,"props":2838,"children":2839},{"emptyLinePlaceholder":537},[2840],{"type":48,"value":540},{"type":42,"tag":322,"props":2842,"children":2843},{"class":324,"line":609},[2844],{"type":42,"tag":322,"props":2845,"children":2846},{},[2847],{"type":48,"value":615},{"type":42,"tag":322,"props":2849,"children":2850},{"class":324,"line":618},[2851],{"type":42,"tag":322,"props":2852,"children":2853},{},[2854],{"type":48,"value":624},{"type":42,"tag":322,"props":2856,"children":2857},{"class":324,"line":627},[2858],{"type":42,"tag":322,"props":2859,"children":2860},{},[2861],{"type":48,"value":633},{"type":42,"tag":322,"props":2863,"children":2864},{"class":324,"line":636},[2865],{"type":42,"tag":322,"props":2866,"children":2867},{},[2868],{"type":48,"value":642},{"type":42,"tag":322,"props":2870,"children":2871},{"class":324,"line":645},[2872],{"type":42,"tag":322,"props":2873,"children":2874},{"emptyLinePlaceholder":537},[2875],{"type":48,"value":540},{"type":42,"tag":322,"props":2877,"children":2878},{"class":324,"line":653},[2879],{"type":42,"tag":322,"props":2880,"children":2881},{},[2882],{"type":48,"value":659},{"type":42,"tag":322,"props":2884,"children":2885},{"class":324,"line":662},[2886],{"type":42,"tag":322,"props":2887,"children":2888},{},[2889],{"type":48,"value":668},{"type":42,"tag":322,"props":2891,"children":2892},{"class":324,"line":671},[2893],{"type":42,"tag":322,"props":2894,"children":2895},{},[2896],{"type":48,"value":677},{"type":42,"tag":322,"props":2898,"children":2899},{"class":324,"line":680},[2900],{"type":42,"tag":322,"props":2901,"children":2902},{},[2903],{"type":48,"value":686},{"type":42,"tag":322,"props":2905,"children":2906},{"class":324,"line":689},[2907],{"type":42,"tag":322,"props":2908,"children":2909},{"emptyLinePlaceholder":537},[2910],{"type":48,"value":540},{"type":42,"tag":322,"props":2912,"children":2913},{"class":324,"line":697},[2914],{"type":42,"tag":322,"props":2915,"children":2916},{},[2917],{"type":48,"value":703},{"type":42,"tag":322,"props":2919,"children":2920},{"class":324,"line":706},[2921],{"type":42,"tag":322,"props":2922,"children":2923},{},[2924],{"type":48,"value":712},{"type":42,"tag":322,"props":2926,"children":2927},{"class":324,"line":715},[2928],{"type":42,"tag":322,"props":2929,"children":2930},{},[2931],{"type":48,"value":721},{"type":42,"tag":322,"props":2933,"children":2934},{"class":324,"line":724},[2935],{"type":42,"tag":322,"props":2936,"children":2937},{},[2938],{"type":48,"value":730},{"type":42,"tag":322,"props":2940,"children":2941},{"class":324,"line":733},[2942],{"type":42,"tag":322,"props":2943,"children":2944},{"emptyLinePlaceholder":537},[2945],{"type":48,"value":540},{"type":42,"tag":322,"props":2947,"children":2948},{"class":324,"line":741},[2949],{"type":42,"tag":322,"props":2950,"children":2951},{},[2952],{"type":48,"value":747},{"type":42,"tag":322,"props":2954,"children":2955},{"class":324,"line":750},[2956],{"type":42,"tag":322,"props":2957,"children":2958},{},[2959],{"type":48,"value":756},{"type":42,"tag":322,"props":2961,"children":2962},{"class":324,"line":759},[2963],{"type":42,"tag":322,"props":2964,"children":2965},{},[2966],{"type":48,"value":765},{"type":42,"tag":322,"props":2968,"children":2969},{"class":324,"line":768},[2970],{"type":42,"tag":322,"props":2971,"children":2972},{},[2973],{"type":48,"value":774},{"type":42,"tag":322,"props":2975,"children":2976},{"class":324,"line":777},[2977],{"type":42,"tag":322,"props":2978,"children":2979},{},[2980],{"type":48,"value":783},{"type":42,"tag":322,"props":2982,"children":2983},{"class":324,"line":786},[2984],{"type":42,"tag":322,"props":2985,"children":2986},{},[2987],{"type":48,"value":792},{"type":42,"tag":322,"props":2989,"children":2990},{"class":324,"line":795},[2991],{"type":42,"tag":322,"props":2992,"children":2993},{},[2994],{"type":48,"value":801},{"type":42,"tag":322,"props":2996,"children":2997},{"class":324,"line":804},[2998],{"type":42,"tag":322,"props":2999,"children":3000},{"emptyLinePlaceholder":537},[3001],{"type":48,"value":540},{"type":42,"tag":322,"props":3003,"children":3004},{"class":324,"line":812},[3005],{"type":42,"tag":322,"props":3006,"children":3007},{},[3008],{"type":48,"value":818},{"type":42,"tag":322,"props":3010,"children":3011},{"class":324,"line":821},[3012],{"type":42,"tag":322,"props":3013,"children":3014},{},[3015],{"type":48,"value":827},{"type":42,"tag":322,"props":3017,"children":3018},{"class":324,"line":830},[3019],{"type":42,"tag":322,"props":3020,"children":3021},{"emptyLinePlaceholder":537},[3022],{"type":48,"value":540},{"type":42,"tag":322,"props":3024,"children":3025},{"class":324,"line":838},[3026],{"type":42,"tag":322,"props":3027,"children":3028},{},[3029],{"type":48,"value":844},{"type":42,"tag":322,"props":3031,"children":3032},{"class":324,"line":847},[3033],{"type":42,"tag":322,"props":3034,"children":3035},{},[3036],{"type":48,"value":853},{"type":42,"tag":322,"props":3038,"children":3039},{"class":324,"line":856},[3040],{"type":42,"tag":322,"props":3041,"children":3042},{},[3043],{"type":48,"value":862},{"type":42,"tag":322,"props":3045,"children":3046},{"class":324,"line":865},[3047],{"type":42,"tag":322,"props":3048,"children":3049},{},[3050],{"type":48,"value":871},{"type":42,"tag":322,"props":3052,"children":3053},{"class":324,"line":874},[3054],{"type":42,"tag":322,"props":3055,"children":3056},{},[3057],{"type":48,"value":880},{"type":42,"tag":322,"props":3059,"children":3060},{"class":324,"line":883},[3061],{"type":42,"tag":322,"props":3062,"children":3063},{"emptyLinePlaceholder":537},[3064],{"type":48,"value":540},{"type":42,"tag":322,"props":3066,"children":3067},{"class":324,"line":891},[3068],{"type":42,"tag":322,"props":3069,"children":3070},{},[3071],{"type":48,"value":897},{"type":42,"tag":322,"props":3073,"children":3074},{"class":324,"line":900},[3075],{"type":42,"tag":322,"props":3076,"children":3077},{},[3078],{"type":48,"value":906},{"type":42,"tag":322,"props":3080,"children":3081},{"class":324,"line":909},[3082],{"type":42,"tag":322,"props":3083,"children":3084},{},[3085],{"type":48,"value":915},{"type":42,"tag":322,"props":3087,"children":3088},{"class":324,"line":918},[3089],{"type":42,"tag":322,"props":3090,"children":3091},{},[3092],{"type":48,"value":924},{"type":42,"tag":322,"props":3094,"children":3095},{"class":324,"line":927},[3096],{"type":42,"tag":322,"props":3097,"children":3098},{"emptyLinePlaceholder":537},[3099],{"type":48,"value":540},{"type":42,"tag":322,"props":3101,"children":3102},{"class":324,"line":935},[3103],{"type":42,"tag":322,"props":3104,"children":3105},{},[3106],{"type":48,"value":941},{"type":42,"tag":322,"props":3108,"children":3109},{"class":324,"line":944},[3110],{"type":42,"tag":322,"props":3111,"children":3112},{},[3113],{"type":48,"value":950},{"type":42,"tag":322,"props":3115,"children":3116},{"class":324,"line":953},[3117],{"type":42,"tag":322,"props":3118,"children":3119},{},[3120],{"type":48,"value":959},{"type":42,"tag":322,"props":3122,"children":3123},{"class":324,"line":962},[3124],{"type":42,"tag":322,"props":3125,"children":3126},{},[3127],{"type":48,"value":968},{"type":42,"tag":51,"props":3129,"children":3130},{},[3131,3132,3137,3138,3143,3144,3149],{"type":48,"value":973},{"type":42,"tag":57,"props":3133,"children":3135},{"className":3134},[],[3136],{"type":48,"value":69},{"type":48,"value":980},{"type":42,"tag":57,"props":3139,"children":3141},{"className":3140},[],[3142],{"type":48,"value":69},{"type":48,"value":987},{"type":42,"tag":57,"props":3145,"children":3147},{"className":3146},[],[3148],{"type":48,"value":993},{"type":48,"value":995},{"type":42,"tag":43,"props":3151,"children":3152},{"id":998},[3153],{"type":48,"value":1001},{"type":42,"tag":51,"props":3155,"children":3156},{},[3157,3158,3163],{"type":48,"value":1006},{"type":42,"tag":57,"props":3159,"children":3161},{"className":3160},[],[3162],{"type":48,"value":69},{"type":48,"value":1013},{"type":42,"tag":1015,"props":3165,"children":3166},{},[3167],{"type":48,"value":1019},{"title":7,"searchDepth":18,"depth":18,"links":3169},[3170,3171,3172,3173,3174,3175,3176],{"id":45,"depth":18,"text":49},{"id":74,"depth":18,"text":77},{"id":147,"depth":18,"text":150},{"id":248,"depth":18,"text":251},{"id":291,"depth":18,"text":1027},{"id":426,"depth":18,"text":1029},{"id":998,"depth":18,"text":1001},{"_path":3178,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":3179,"description":3180,"date":10,"readingTime":618,"category":12,"tags":3181,"difficulty":17,"module":5,"step":353,"journeys":3182,"roles":3183,"learnMore":3184,"author":3197,"body":3198,"_type":519,"_id":4133,"_source":1032,"_file":4134,"_stem":4135,"_extension":1035},"/tutorials/stock-analyst-101/ingest-data","Ingest FMP, Yahoo Finance, and FRED","Have the AI agent write ingestr assets for three data sources - company fundamentals, stock prices, and US macro - and pull them into DuckDB.",[14,15,16,22],[20],[22,23],[3185,3188,3191,3194],{"label":3186,"url":3187},"ingestr supported sources","https://bruin-data.github.io/ingestr/supported-sources.html",{"label":3189,"url":3190},"Bruin ingestr asset type","https://getbruin.com/docs/bruin/assets/ingestr.html",{"label":3192,"url":3193},"FRED API key signup","https://fred.stlouisfed.org/docs/api/api_key.html",{"label":3195,"url":3196},"FMP API docs","https://site.financialmodelingprep.com/developer/docs",{"name":35,"role":36,"image":37},{"type":39,"children":3199,"toc":4122},[3200,3204,3209,3213,3218,3251,3256,3262,3267,3302,3314,3320,3324,3439,3487,3499,3536,3542,3547,3732,3737,3925,3937,3943,3948,3963,3983,3989,3994,4032,4037,4043,4102,4106,4118],{"type":42,"tag":43,"props":3201,"children":3202},{"id":45},[3203],{"type":48,"value":49},{"type":42,"tag":51,"props":3205,"children":3206},{},[3207],{"type":48,"value":3208},"Get free API keys for FMP and FRED (Yahoo Finance needs none), add them to your project config, and have the AI agent scaffold three ingestr assets. Then run the pipeline once to populate DuckDB.",{"type":42,"tag":43,"props":3210,"children":3211},{"id":74},[3212],{"type":48,"value":77},{"type":42,"tag":51,"props":3214,"children":3215},{},[3216],{"type":48,"value":3217},"This is the entire data-import layer of a stock analyst's stack, in one step:",{"type":42,"tag":84,"props":3219,"children":3220},{},[3221,3231,3241],{"type":42,"tag":88,"props":3222,"children":3223},{},[3224,3229],{"type":42,"tag":94,"props":3225,"children":3226},{},[3227],{"type":48,"value":3228},"FMP",{"type":48,"value":3230}," gives you quarterly financials and ratios - the numbers every analyst looks at first",{"type":42,"tag":88,"props":3232,"children":3233},{},[3234,3239],{"type":42,"tag":94,"props":3235,"children":3236},{},[3237],{"type":48,"value":3238},"Yahoo Finance",{"type":48,"value":3240}," gives you daily price bars (open / high / low / close / volume) - how the market has priced the company",{"type":42,"tag":88,"props":3242,"children":3243},{},[3244,3249],{"type":42,"tag":94,"props":3245,"children":3246},{},[3247],{"type":48,"value":3248},"FRED",{"type":48,"value":3250}," gives you the macro backdrop - rates, inflation, unemployment, the yield curve - the regime your picks live inside of",{"type":42,"tag":51,"props":3252,"children":3253},{},[3254],{"type":48,"value":3255},"Most beginners stop at one source and build shallow analysis. With all three in the same database you can ask questions that combine them, which is where the real signal lives.",{"type":42,"tag":43,"props":3257,"children":3259},{"id":3258},"_1-get-your-free-api-keys",[3260],{"type":48,"value":3261},"1. Get your free API keys",{"type":42,"tag":51,"props":3263,"children":3264},{},[3265],{"type":48,"value":3266},"Two signups, 1 minute each. Yahoo Finance needs no key.",{"type":42,"tag":84,"props":3268,"children":3269},{},[3270,3287],{"type":42,"tag":88,"props":3271,"children":3272},{},[3273,3277,3279,3285],{"type":42,"tag":94,"props":3274,"children":3275},{},[3276],{"type":48,"value":3228},{"type":48,"value":3278}," - ",{"type":42,"tag":1913,"props":3280,"children":3282},{"href":3196,"rel":3281},[1917],[3283],{"type":48,"value":3284},"sign up here",{"type":48,"value":3286}," → free plan → copy the API key",{"type":42,"tag":88,"props":3288,"children":3289},{},[3290,3294,3295,3300],{"type":42,"tag":94,"props":3291,"children":3292},{},[3293],{"type":48,"value":3248},{"type":48,"value":3278},{"type":42,"tag":1913,"props":3296,"children":3298},{"href":3193,"rel":3297},[1917],[3299],{"type":48,"value":3284},{"type":48,"value":3301}," → click \"Request API Key\" → copy it",{"type":42,"tag":51,"props":3303,"children":3304},{},[3305,3307,3312],{"type":48,"value":3306},"Keep both keys in a note somewhere. You'll paste them into ",{"type":42,"tag":57,"props":3308,"children":3310},{"className":3309},[],[3311],{"type":48,"value":106},{"type":48,"value":3313}," in the next step.",{"type":42,"tag":43,"props":3315,"children":3317},{"id":3316},"_2-add-the-source-connections",[3318],{"type":48,"value":3319},"2. Add the source connections",{"type":42,"tag":51,"props":3321,"children":3322},{},[3323],{"type":48,"value":461},{"type":42,"tag":157,"props":3325,"children":3326},{},[3327,3347,3419],{"type":42,"tag":51,"props":3328,"children":3329},{},[3330,3332,3337,3339,3345],{"type":48,"value":3331},"Add three new connections to ",{"type":42,"tag":57,"props":3333,"children":3335},{"className":3334},[],[3336],{"type":48,"value":106},{"type":48,"value":3338}," under ",{"type":42,"tag":57,"props":3340,"children":3342},{"className":3341},[],[3343],{"type":48,"value":3344},"environments.default.connections",{"type":48,"value":3346},":",{"type":42,"tag":203,"props":3348,"children":3349},{},[3350,3376,3395],{"type":42,"tag":88,"props":3351,"children":3352},{},[3353,3354,3360,3362,3368,3370],{"type":48,"value":113},{"type":42,"tag":57,"props":3355,"children":3357},{"className":3356},[],[3358],{"type":48,"value":3359},"fmp",{"type":48,"value":3361}," connection named ",{"type":42,"tag":57,"props":3363,"children":3365},{"className":3364},[],[3366],{"type":48,"value":3367},"fmp-default",{"type":48,"value":3369}," with API key ",{"type":42,"tag":57,"props":3371,"children":3373},{"className":3372},[],[3374],{"type":48,"value":3375},"\u003CYOUR_FMP_KEY>",{"type":42,"tag":88,"props":3377,"children":3378},{},[3379,3380,3386,3387,3393],{"type":48,"value":92},{"type":42,"tag":57,"props":3381,"children":3383},{"className":3382},[],[3384],{"type":48,"value":3385},"yahoo_finance",{"type":48,"value":3361},{"type":42,"tag":57,"props":3388,"children":3390},{"className":3389},[],[3391],{"type":48,"value":3392},"yahoo-default",{"type":48,"value":3394}," (no credentials needed)",{"type":42,"tag":88,"props":3396,"children":3397},{},[3398,3399,3405,3406,3412,3413],{"type":48,"value":92},{"type":42,"tag":57,"props":3400,"children":3402},{"className":3401},[],[3403],{"type":48,"value":3404},"fred",{"type":48,"value":3361},{"type":42,"tag":57,"props":3407,"children":3409},{"className":3408},[],[3410],{"type":48,"value":3411},"fred-default",{"type":48,"value":3369},{"type":42,"tag":57,"props":3414,"children":3416},{"className":3415},[],[3417],{"type":48,"value":3418},"\u003CYOUR_FRED_KEY>",{"type":42,"tag":51,"props":3420,"children":3421},{},[3422,3424,3429,3431,3437],{"type":48,"value":3423},"Use the ingestr docs at ",{"type":42,"tag":1913,"props":3425,"children":3427},{"href":3187,"rel":3426},[1917],[3428],{"type":48,"value":3187},{"type":48,"value":3430}," for the exact field names. Then run ",{"type":42,"tag":57,"props":3432,"children":3434},{"className":3433},[],[3435],{"type":48,"value":3436},"bruin connections test",{"type":48,"value":3438}," for each and show me the output.",{"type":42,"tag":2058,"props":3440,"children":3441},{},[3442],{"type":42,"tag":51,"props":3443,"children":3444},{},[3445,3450,3452,3457,3459,3464,3466,3471,3473,3478,3480,3485],{"type":42,"tag":94,"props":3446,"children":3447},{},[3448],{"type":48,"value":3449},"Don't want to hand the agent your keys?",{"type":48,"value":3451}," Ask it instead to scaffold the connections in ",{"type":42,"tag":57,"props":3453,"children":3455},{"className":3454},[],[3456],{"type":48,"value":106},{"type":48,"value":3458}," with ",{"type":42,"tag":94,"props":3460,"children":3461},{},[3462],{"type":48,"value":3463},"placeholder values",{"type":48,"value":3465}," (e.g. ",{"type":42,"tag":57,"props":3467,"children":3469},{"className":3468},[],[3470],{"type":48,"value":3375},{"type":48,"value":3472},", ",{"type":42,"tag":57,"props":3474,"children":3476},{"className":3475},[],[3477],{"type":48,"value":3418},{"type":48,"value":3479},"). Then open ",{"type":42,"tag":57,"props":3481,"children":3483},{"className":3482},[],[3484],{"type":48,"value":106},{"type":48,"value":3486}," yourself and paste the real keys in. The file is git-ignored by default, so they stay local.",{"type":42,"tag":51,"props":3488,"children":3489},{},[3490,3492,3497],{"type":48,"value":3491},"When the agent finishes, ",{"type":42,"tag":57,"props":3493,"children":3495},{"className":3494},[],[3496],{"type":48,"value":106},{"type":48,"value":3498}," will have four connections total: your DuckDB destination from Step 2 plus the three new sources.",{"type":42,"tag":2058,"props":3500,"children":3501},{},[3502],{"type":42,"tag":51,"props":3503,"children":3504},{},[3505,3510,3512,3517,3519,3525,3527,3534],{"type":42,"tag":94,"props":3506,"children":3507},{},[3508],{"type":48,"value":3509},"Security note.",{"type":48,"value":3511}," ",{"type":42,"tag":57,"props":3513,"children":3515},{"className":3514},[],[3516],{"type":48,"value":106},{"type":48,"value":3518}," is added to ",{"type":42,"tag":57,"props":3520,"children":3522},{"className":3521},[],[3523],{"type":48,"value":3524},".gitignore",{"type":48,"value":3526}," by default - your keys won't end up in git. If you're sharing the project, use environment variables instead; ",{"type":42,"tag":1913,"props":3528,"children":3531},{"href":3529,"rel":3530},"https://getbruin.com/docs/bruin/secrets/overview.html",[1917],[3532],{"type":48,"value":3533},"the docs",{"type":48,"value":3535}," show how.",{"type":42,"tag":43,"props":3537,"children":3539},{"id":3538},"_3-have-the-agent-write-three-ingestr-assets",[3540],{"type":48,"value":3541},"3. Have the agent write three ingestr assets",{"type":42,"tag":51,"props":3543,"children":3544},{},[3545],{"type":48,"value":3546},"Now the good part. Prompt:",{"type":42,"tag":157,"props":3548,"children":3549},{},[3550,3563,3608,3647,3727],{"type":42,"tag":51,"props":3551,"children":3552},{},[3553,3555,3561],{"type":48,"value":3554},"In ",{"type":42,"tag":57,"props":3556,"children":3558},{"className":3557},[],[3559],{"type":48,"value":3560},"stock-analyst-101/assets/",{"type":48,"value":3562},", create three ingestr assets using the ingestr documentation as reference:",{"type":42,"tag":51,"props":3564,"children":3565},{},[3566,3575,3577,3582,3584,3590,3592,3598,3600,3606],{"type":42,"tag":94,"props":3567,"children":3568},{},[3569],{"type":42,"tag":57,"props":3570,"children":3572},{"className":3571},[],[3573],{"type":48,"value":3574},"fmp_fundamentals.asset.yml",{"type":48,"value":3576}," - pull quarterly income statement, balance sheet, and cash flow for tickers AAPL, MSFT, NVDA, GOOGL, AMZN. Destination: ",{"type":42,"tag":57,"props":3578,"children":3580},{"className":3579},[],[3581],{"type":48,"value":178},{"type":48,"value":3583},", schema ",{"type":42,"tag":57,"props":3585,"children":3587},{"className":3586},[],[3588],{"type":48,"value":3589},"raw",{"type":48,"value":3591},", table ",{"type":42,"tag":57,"props":3593,"children":3595},{"className":3594},[],[3596],{"type":48,"value":3597},"fmp_fundamentals",{"type":48,"value":3599},". Use merge strategy on ",{"type":42,"tag":57,"props":3601,"children":3603},{"className":3602},[],[3604],{"type":48,"value":3605},"symbol + date",{"type":48,"value":3607},".",{"type":42,"tag":51,"props":3609,"children":3610},{},[3611,3620,3622,3627,3628,3633,3634,3640,3641,3646],{"type":42,"tag":94,"props":3612,"children":3613},{},[3614],{"type":42,"tag":57,"props":3615,"children":3617},{"className":3616},[],[3618],{"type":48,"value":3619},"yahoo_prices.asset.yml",{"type":48,"value":3621}," - pull daily OHLCV prices for the same 5 tickers from 2020-01-01 to today. Destination: ",{"type":42,"tag":57,"props":3623,"children":3625},{"className":3624},[],[3626],{"type":48,"value":178},{"type":48,"value":3583},{"type":42,"tag":57,"props":3629,"children":3631},{"className":3630},[],[3632],{"type":48,"value":3589},{"type":48,"value":3591},{"type":42,"tag":57,"props":3635,"children":3637},{"className":3636},[],[3638],{"type":48,"value":3639},"yahoo_prices",{"type":48,"value":3599},{"type":42,"tag":57,"props":3642,"children":3644},{"className":3643},[],[3645],{"type":48,"value":3605},{"type":48,"value":3607},{"type":42,"tag":51,"props":3648,"children":3649},{},[3650,3659,3661,3667,3669,3675,3677,3683,3685,3691,3693,3699,3701,3706,3707,3712,3713,3719,3720,3726],{"type":42,"tag":94,"props":3651,"children":3652},{},[3653],{"type":42,"tag":57,"props":3654,"children":3656},{"className":3655},[],[3657],{"type":48,"value":3658},"fred_macro.asset.yml",{"type":48,"value":3660}," - pull these FRED series: ",{"type":42,"tag":57,"props":3662,"children":3664},{"className":3663},[],[3665],{"type":48,"value":3666},"FEDFUNDS",{"type":48,"value":3668}," (Fed funds rate), ",{"type":42,"tag":57,"props":3670,"children":3672},{"className":3671},[],[3673],{"type":48,"value":3674},"CPIAUCSL",{"type":48,"value":3676}," (CPI), ",{"type":42,"tag":57,"props":3678,"children":3680},{"className":3679},[],[3681],{"type":48,"value":3682},"UNRATE",{"type":48,"value":3684}," (unemployment), ",{"type":42,"tag":57,"props":3686,"children":3688},{"className":3687},[],[3689],{"type":48,"value":3690},"T10Y2Y",{"type":48,"value":3692}," (10Y-2Y yield spread), ",{"type":42,"tag":57,"props":3694,"children":3696},{"className":3695},[],[3697],{"type":48,"value":3698},"GDPC1",{"type":48,"value":3700}," (real GDP). Destination: ",{"type":42,"tag":57,"props":3702,"children":3704},{"className":3703},[],[3705],{"type":48,"value":178},{"type":48,"value":3583},{"type":42,"tag":57,"props":3708,"children":3710},{"className":3709},[],[3711],{"type":48,"value":3589},{"type":48,"value":3591},{"type":42,"tag":57,"props":3714,"children":3716},{"className":3715},[],[3717],{"type":48,"value":3718},"fred_macro",{"type":48,"value":3599},{"type":42,"tag":57,"props":3721,"children":3723},{"className":3722},[],[3724],{"type":48,"value":3725},"series_id + date",{"type":48,"value":3607},{"type":42,"tag":51,"props":3728,"children":3729},{},[3730],{"type":48,"value":3731},"Before writing the files, show me each YAML and explain what it does. Don't run anything yet.",{"type":42,"tag":51,"props":3733,"children":3734},{},[3735],{"type":48,"value":3736},"The agent will produce three YAML files. Read them - they should look roughly like:",{"type":42,"tag":258,"props":3738,"children":3740},{"className":314,"code":3739,"language":316,"meta":7,"style":7},"name: raw.fmp_fundamentals\ntype: ingestr\nparameters:\n  source_connection: fmp-default\n  source_table: \"income-statement,balance-sheet-statement,cash-flow-statement\"\n  destination: duckdb\n  destination_connection: duckdb-default\n  incremental_strategy: merge\n  incremental_key: \"symbol,date\"\n  interval_start: \"2020-01-01\"\n  tickers: \"AAPL,MSFT,NVDA,GOOGL,AMZN\"\n",[3741],{"type":42,"tag":57,"props":3742,"children":3743},{"__ignoreMap":7},[3744,3760,3777,3789,3806,3823,3840,3857,3874,3891,3908],{"type":42,"tag":322,"props":3745,"children":3746},{"class":324,"line":325},[3747,3751,3755],{"type":42,"tag":322,"props":3748,"children":3749},{"style":329},[3750],{"type":48,"value":389},{"type":42,"tag":322,"props":3752,"children":3753},{"style":335},[3754],{"type":48,"value":394},{"type":42,"tag":322,"props":3756,"children":3757},{"style":397},[3758],{"type":48,"value":3759},"raw.fmp_fundamentals\n",{"type":42,"tag":322,"props":3761,"children":3762},{"class":324,"line":18},[3763,3768,3772],{"type":42,"tag":322,"props":3764,"children":3765},{"style":329},[3766],{"type":48,"value":3767},"type",{"type":42,"tag":322,"props":3769,"children":3770},{"style":335},[3771],{"type":48,"value":394},{"type":42,"tag":322,"props":3773,"children":3774},{"style":397},[3775],{"type":48,"value":3776},"ingestr\n",{"type":42,"tag":322,"props":3778,"children":3779},{"class":324,"line":353},[3780,3785],{"type":42,"tag":322,"props":3781,"children":3782},{"style":329},[3783],{"type":48,"value":3784},"parameters",{"type":42,"tag":322,"props":3786,"children":3787},{"style":335},[3788],{"type":48,"value":338},{"type":42,"tag":322,"props":3790,"children":3791},{"class":324,"line":366},[3792,3797,3801],{"type":42,"tag":322,"props":3793,"children":3794},{"style":329},[3795],{"type":48,"value":3796},"  source_connection",{"type":42,"tag":322,"props":3798,"children":3799},{"style":335},[3800],{"type":48,"value":394},{"type":42,"tag":322,"props":3802,"children":3803},{"style":397},[3804],{"type":48,"value":3805},"fmp-default\n",{"type":42,"tag":322,"props":3807,"children":3808},{"class":324,"line":11},[3809,3814,3818],{"type":42,"tag":322,"props":3810,"children":3811},{"style":329},[3812],{"type":48,"value":3813},"  source_table",{"type":42,"tag":322,"props":3815,"children":3816},{"style":335},[3817],{"type":48,"value":394},{"type":42,"tag":322,"props":3819,"children":3820},{"style":397},[3821],{"type":48,"value":3822},"\"income-statement,balance-sheet-statement,cash-flow-statement\"\n",{"type":42,"tag":322,"props":3824,"children":3825},{"class":324,"line":403},[3826,3831,3835],{"type":42,"tag":322,"props":3827,"children":3828},{"style":329},[3829],{"type":48,"value":3830},"  destination",{"type":42,"tag":322,"props":3832,"children":3833},{"style":335},[3834],{"type":48,"value":394},{"type":42,"tag":322,"props":3836,"children":3837},{"style":397},[3838],{"type":48,"value":3839},"duckdb\n",{"type":42,"tag":322,"props":3841,"children":3842},{"class":324,"line":574},[3843,3848,3852],{"type":42,"tag":322,"props":3844,"children":3845},{"style":329},[3846],{"type":48,"value":3847},"  destination_connection",{"type":42,"tag":322,"props":3849,"children":3850},{"style":335},[3851],{"type":48,"value":394},{"type":42,"tag":322,"props":3853,"children":3854},{"style":397},[3855],{"type":48,"value":3856},"duckdb-default\n",{"type":42,"tag":322,"props":3858,"children":3859},{"class":324,"line":583},[3860,3865,3869],{"type":42,"tag":322,"props":3861,"children":3862},{"style":329},[3863],{"type":48,"value":3864},"  incremental_strategy",{"type":42,"tag":322,"props":3866,"children":3867},{"style":335},[3868],{"type":48,"value":394},{"type":42,"tag":322,"props":3870,"children":3871},{"style":397},[3872],{"type":48,"value":3873},"merge\n",{"type":42,"tag":322,"props":3875,"children":3876},{"class":324,"line":592},[3877,3882,3886],{"type":42,"tag":322,"props":3878,"children":3879},{"style":329},[3880],{"type":48,"value":3881},"  incremental_key",{"type":42,"tag":322,"props":3883,"children":3884},{"style":335},[3885],{"type":48,"value":394},{"type":42,"tag":322,"props":3887,"children":3888},{"style":397},[3889],{"type":48,"value":3890},"\"symbol,date\"\n",{"type":42,"tag":322,"props":3892,"children":3893},{"class":324,"line":601},[3894,3899,3903],{"type":42,"tag":322,"props":3895,"children":3896},{"style":329},[3897],{"type":48,"value":3898},"  interval_start",{"type":42,"tag":322,"props":3900,"children":3901},{"style":335},[3902],{"type":48,"value":394},{"type":42,"tag":322,"props":3904,"children":3905},{"style":397},[3906],{"type":48,"value":3907},"\"2020-01-01\"\n",{"type":42,"tag":322,"props":3909,"children":3910},{"class":324,"line":609},[3911,3916,3920],{"type":42,"tag":322,"props":3912,"children":3913},{"style":329},[3914],{"type":48,"value":3915},"  tickers",{"type":42,"tag":322,"props":3917,"children":3918},{"style":335},[3919],{"type":48,"value":394},{"type":42,"tag":322,"props":3921,"children":3922},{"style":397},[3923],{"type":48,"value":3924},"\"AAPL,MSFT,NVDA,GOOGL,AMZN\"\n",{"type":42,"tag":51,"props":3926,"children":3927},{},[3928,3930,3935],{"type":48,"value":3929},"Field names vary by source - the ingestr docs are the source of truth. Trust what the agent writes but glance at the YAML to make sure the ",{"type":42,"tag":94,"props":3931,"children":3932},{},[3933],{"type":48,"value":3934},"destination, schema, and table name",{"type":48,"value":3936}," match what you asked for.",{"type":42,"tag":43,"props":3938,"children":3940},{"id":3939},"_4-run-the-pipeline",[3941],{"type":48,"value":3942},"4. Run the pipeline",{"type":42,"tag":51,"props":3944,"children":3945},{},[3946],{"type":48,"value":3947},"One more prompt:",{"type":42,"tag":157,"props":3949,"children":3950},{},[3951],{"type":42,"tag":51,"props":3952,"children":3953},{},[3954,3955,3961],{"type":48,"value":210},{"type":42,"tag":57,"props":3956,"children":3958},{"className":3957},[],[3959],{"type":48,"value":3960},"bruin run stock-analyst-101/",{"type":48,"value":3962}," and stream the output. Tell me which assets succeeded and any that failed.",{"type":42,"tag":51,"props":3964,"children":3965},{},[3966,3968,3974,3976,3982],{"type":48,"value":3967},"This kicks off all three ingestions in parallel. First run can take 2–5 minutes depending on how much history Yahoo returns. When it finishes, you'll have three tables in ",{"type":42,"tag":57,"props":3969,"children":3971},{"className":3970},[],[3972],{"type":48,"value":3973},"raw.*",{"type":48,"value":3975}," inside ",{"type":42,"tag":57,"props":3977,"children":3979},{"className":3978},[],[3980],{"type":48,"value":3981},"stock.duckdb",{"type":48,"value":3607},{"type":42,"tag":43,"props":3984,"children":3986},{"id":3985},"_5-peek-at-what-landed",[3987],{"type":48,"value":3988},"5. Peek at what landed",{"type":42,"tag":51,"props":3990,"children":3991},{},[3992],{"type":48,"value":3993},"Prompt:",{"type":42,"tag":157,"props":3995,"children":3996},{},[3997],{"type":42,"tag":51,"props":3998,"children":3999},{},[4000,4002,4008,4010,4016,4018,4024,4025,4031],{"type":48,"value":4001},"Using ",{"type":42,"tag":57,"props":4003,"children":4005},{"className":4004},[],[4006],{"type":48,"value":4007},"bruin query",{"type":48,"value":4009},", show me ",{"type":42,"tag":57,"props":4011,"children":4013},{"className":4012},[],[4014],{"type":48,"value":4015},"SELECT COUNT(*), MIN(date), MAX(date) FROM raw.yahoo_prices GROUP BY symbol",{"type":48,"value":4017},". Do the same shape of count for ",{"type":42,"tag":57,"props":4019,"children":4021},{"className":4020},[],[4022],{"type":48,"value":4023},"raw.fmp_fundamentals",{"type":48,"value":491},{"type":42,"tag":57,"props":4026,"children":4028},{"className":4027},[],[4029],{"type":48,"value":4030},"raw.fred_macro",{"type":48,"value":3607},{"type":42,"tag":51,"props":4033,"children":4034},{},[4035],{"type":48,"value":4036},"You should see a few thousand price rows per ticker, ~20 fundamental rows per ticker (quarterly history), and one row per (series × date) for the macro table.",{"type":42,"tag":43,"props":4038,"children":4040},{"id":4039},"troubleshooting",[4041],{"type":48,"value":4042},"Troubleshooting",{"type":42,"tag":84,"props":4044,"children":4045},{},[4046,4056,4082,4092],{"type":42,"tag":88,"props":4047,"children":4048},{},[4049,4054],{"type":42,"tag":94,"props":4050,"children":4051},{},[4052],{"type":48,"value":4053},"FMP \"API limit reached\"",{"type":48,"value":4055}," - the free plan is generous but rate-limited. Wait a minute and re-run.",{"type":42,"tag":88,"props":4057,"children":4058},{},[4059,4064,4066,4072,4074,4080],{"type":42,"tag":94,"props":4060,"children":4061},{},[4062],{"type":48,"value":4063},"Yahoo Finance \"No data for ticker\"",{"type":48,"value":4065}," - check the ticker symbol. ",{"type":42,"tag":57,"props":4067,"children":4069},{"className":4068},[],[4070],{"type":48,"value":4071},"BRK.B",{"type":48,"value":4073}," needs to be ",{"type":42,"tag":57,"props":4075,"children":4077},{"className":4076},[],[4078],{"type":48,"value":4079},"BRK-B",{"type":48,"value":4081}," for Yahoo.",{"type":42,"tag":88,"props":4083,"children":4084},{},[4085,4090],{"type":42,"tag":94,"props":4086,"children":4087},{},[4088],{"type":48,"value":4089},"FRED \"Invalid API key\"",{"type":48,"value":4091}," - keys are case-sensitive and have no spaces. Re-copy from fredapi settings.",{"type":42,"tag":88,"props":4093,"children":4094},{},[4095,4100],{"type":42,"tag":94,"props":4096,"children":4097},{},[4098],{"type":48,"value":4099},"DuckDB file locked",{"type":48,"value":4101}," - you have DuckDB open in another process (maybe a desktop app). Close it, re-run.",{"type":42,"tag":43,"props":4103,"children":4104},{"id":998},[4105],{"type":48,"value":1001},{"type":42,"tag":51,"props":4107,"children":4108},{},[4109,4111,4116],{"type":48,"value":4110},"You just built a three-source financial data stack on a laptop, with zero SQL written by you. Every byte of it lives in ",{"type":42,"tag":57,"props":4112,"children":4114},{"className":4113},[],[4115],{"type":48,"value":3981},{"type":48,"value":4117}," - one file, portable, inspectable with any SQL tool. Next step: teach the AI agent what these tables mean so it can reason about them accurately.",{"type":42,"tag":1015,"props":4119,"children":4120},{},[4121],{"type":48,"value":1019},{"title":7,"searchDepth":18,"depth":18,"links":4123},[4124,4125,4126,4127,4128,4129,4130,4131,4132],{"id":45,"depth":18,"text":49},{"id":74,"depth":18,"text":77},{"id":3258,"depth":18,"text":3261},{"id":3316,"depth":18,"text":3319},{"id":3538,"depth":18,"text":3541},{"id":3939,"depth":18,"text":3942},{"id":3985,"depth":18,"text":3988},{"id":4039,"depth":18,"text":4042},{"id":998,"depth":18,"text":1001},"content:tutorials:stock-analyst-101:ingest-data.md","tutorials/stock-analyst-101/ingest-data.md","tutorials/stock-analyst-101/ingest-data",{"_path":4137,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":4138,"description":4139,"date":10,"readingTime":618,"category":12,"tags":4140,"difficulty":17,"module":5,"step":366,"journeys":4142,"roles":4143,"learnMore":4144,"author":4154,"body":4155,"_type":519,"_id":5074,"_source":1032,"_file":5075,"_stem":5076,"_extension":1035},"/tutorials/stock-analyst-101/transform-reports","Build Staging + Report Layers","Add a clean middle layer on top of the raw data, then build a final report table that joins fundamentals, prices, and macro - the analysis-ready table your AI agent will query.",[14,15,16,22,4141],"SQL",[20],[22,23],[4145,4148,4151],{"label":4146,"url":4147},"Bruin SQL asset type","https://getbruin.com/docs/bruin/assets/sql.html",{"label":4149,"url":4150},"Bruin materializations","https://getbruin.com/docs/bruin/assets/materialization.html",{"label":4152,"url":4153},"Bruin quality checks","https://getbruin.com/docs/bruin/quality-checks/overview.html",{"name":35,"role":36,"image":37},{"type":39,"children":4156,"toc":5065},[4157,4161,4166,4201,4205,4210,4215,4257,4269,4275,4279,4608,4621,4627,4631,4872,4877,4883,4887,4998,5003,5009,5014,5023,5038,5056,5060],{"type":42,"tag":43,"props":4158,"children":4159},{"id":45},[4160],{"type":48,"value":49},{"type":42,"tag":51,"props":4162,"children":4163},{},[4164],{"type":48,"value":4165},"Ask the agent to add two new layers of SQL assets on top of the raw tables from Step 3:",{"type":42,"tag":203,"props":4167,"children":4168},{},[4169,4185],{"type":42,"tag":88,"props":4170,"children":4171},{},[4172,4183],{"type":42,"tag":94,"props":4173,"children":4174},{},[4175,4181],{"type":42,"tag":57,"props":4176,"children":4178},{"className":4177},[],[4179],{"type":48,"value":4180},"staging.*",{"type":48,"value":4182}," views",{"type":48,"value":4184}," - one per raw source, cleaning and typing the data, computing basic derived columns",{"type":42,"tag":88,"props":4186,"children":4187},{},[4188,4199],{"type":42,"tag":94,"props":4189,"children":4190},{},[4191,4197],{"type":42,"tag":57,"props":4192,"children":4194},{"className":4193},[],[4195],{"type":48,"value":4196},"reports.*",{"type":48,"value":4198}," table",{"type":48,"value":4200}," - the analysis-ready joined surface that the AI will query in Step 6",{"type":42,"tag":43,"props":4202,"children":4203},{"id":74},[4204],{"type":48,"value":77},{"type":42,"tag":51,"props":4206,"children":4207},{},[4208],{"type":48,"value":4209},"Your raw tables are the source of truth - but they're messy: units in micros, timezones in UTC, fundamentals reported 30–60 days after fiscal quarter end, FRED series coming in at three different frequencies. Asking analytical questions directly against raw means re-deriving the same transforms every time.",{"type":42,"tag":51,"props":4211,"children":4212},{},[4213],{"type":48,"value":4214},"The layered pattern fixes that once:",{"type":42,"tag":84,"props":4216,"children":4217},{},[4218,4231,4244],{"type":42,"tag":88,"props":4219,"children":4220},{},[4221,4229],{"type":42,"tag":94,"props":4222,"children":4223},{},[4224],{"type":42,"tag":57,"props":4225,"children":4227},{"className":4226},[],[4228],{"type":48,"value":3973},{"type":48,"value":4230}," - untouched copy of what the source sent (Step 3 output)",{"type":42,"tag":88,"props":4232,"children":4233},{},[4234,4242],{"type":42,"tag":94,"props":4235,"children":4236},{},[4237],{"type":42,"tag":57,"props":4238,"children":4240},{"className":4239},[],[4241],{"type":48,"value":4180},{"type":48,"value":4243}," - cleaned, typed, deduplicated. One view per source.",{"type":42,"tag":88,"props":4245,"children":4246},{},[4247,4255],{"type":42,"tag":94,"props":4248,"children":4249},{},[4250],{"type":42,"tag":57,"props":4251,"children":4253},{"className":4252},[],[4254],{"type":48,"value":4196},{"type":48,"value":4256}," - business-ready joins with pre-computed metrics (FCF margin, TTM, quarterly return, yield curve regime, etc.)",{"type":42,"tag":51,"props":4258,"children":4259},{},[4260,4262,4267],{"type":48,"value":4261},"Once this layer exists, you ask questions against ",{"type":42,"tag":57,"props":4263,"children":4265},{"className":4264},[],[4266],{"type":48,"value":4196},{"type":48,"value":4268}," and the AI doesn't have to re-derive FCF margin or re-align fundamentals-to-prices every session. Faster, cheaper, less room for mistakes.",{"type":42,"tag":43,"props":4270,"children":4272},{"id":4271},"_1-scaffold-the-staging-views",[4273],{"type":48,"value":4274},"1. Scaffold the staging views",{"type":42,"tag":51,"props":4276,"children":4277},{},[4278],{"type":48,"value":461},{"type":42,"tag":157,"props":4280,"children":4281},{},[4282,4307,4327,4393,4412,4466,4485,4574,4603],{"type":42,"tag":51,"props":4283,"children":4284},{},[4285,4286,4291,4293,4298,4300,4306],{"type":48,"value":3554},{"type":42,"tag":57,"props":4287,"children":4289},{"className":4288},[],[4290],{"type":48,"value":3560},{"type":48,"value":4292},", create three Bruin SQL assets for the staging layer. All should materialize as ",{"type":42,"tag":94,"props":4294,"children":4295},{},[4296],{"type":48,"value":4297},"views",{"type":48,"value":4299}," (cheap, always fresh) with schema ",{"type":42,"tag":57,"props":4301,"children":4303},{"className":4302},[],[4304],{"type":48,"value":4305},"staging",{"type":48,"value":3607},{"type":42,"tag":51,"props":4308,"children":4309},{},[4310,4319,4321],{"type":42,"tag":94,"props":4311,"children":4312},{},[4313],{"type":42,"tag":57,"props":4314,"children":4316},{"className":4315},[],[4317],{"type":48,"value":4318},"staging/fundamentals.sql",{"type":48,"value":4320}," → ",{"type":42,"tag":57,"props":4322,"children":4324},{"className":4323},[],[4325],{"type":48,"value":4326},"staging.fundamentals",{"type":42,"tag":84,"props":4328,"children":4329},{},[4330,4340,4361,4372,4377,4388],{"type":42,"tag":88,"props":4331,"children":4332},{},[4333,4335],{"type":48,"value":4334},"Source: ",{"type":42,"tag":57,"props":4336,"children":4338},{"className":4337},[],[4339],{"type":48,"value":4023},{"type":42,"tag":88,"props":4341,"children":4342},{},[4343,4345,4351,4353,4359],{"type":48,"value":4344},"Uppercase ",{"type":42,"tag":57,"props":4346,"children":4348},{"className":4347},[],[4349],{"type":48,"value":4350},"symbol",{"type":48,"value":4352},", cast ",{"type":42,"tag":57,"props":4354,"children":4356},{"className":4355},[],[4357],{"type":48,"value":4358},"date",{"type":48,"value":4360}," to DATE",{"type":42,"tag":88,"props":4362,"children":4363},{},[4364,4366],{"type":48,"value":4365},"Dedupe on (symbol, date) using ",{"type":42,"tag":57,"props":4367,"children":4369},{"className":4368},[],[4370],{"type":48,"value":4371},"QUALIFY ROW_NUMBER() OVER (PARTITION BY symbol, date ORDER BY date DESC) = 1",{"type":42,"tag":88,"props":4373,"children":4374},{},[4375],{"type":48,"value":4376},"Pivot income-statement / balance-sheet / cash-flow rows into one row per (symbol, fiscal_quarter_end)",{"type":42,"tag":88,"props":4378,"children":4379},{},[4380,4382],{"type":48,"value":4381},"Compute ",{"type":42,"tag":57,"props":4383,"children":4385},{"className":4384},[],[4386],{"type":48,"value":4387},"free_cash_flow = operating_cash_flow - capital_expenditures",{"type":42,"tag":88,"props":4389,"children":4390},{},[4391],{"type":48,"value":4392},"Keep: symbol, fiscal_quarter_end, revenue, gross_profit, operating_income, net_income, eps_diluted, operating_cash_flow, capital_expenditures, free_cash_flow, total_assets, total_liabilities, shareholders_equity",{"type":42,"tag":51,"props":4394,"children":4395},{},[4396,4405,4406],{"type":42,"tag":94,"props":4397,"children":4398},{},[4399],{"type":42,"tag":57,"props":4400,"children":4402},{"className":4401},[],[4403],{"type":48,"value":4404},"staging/prices.sql",{"type":48,"value":4320},{"type":42,"tag":57,"props":4407,"children":4409},{"className":4408},[],[4410],{"type":48,"value":4411},"staging.prices",{"type":42,"tag":84,"props":4413,"children":4414},{},[4415,4425,4441,4446,4456,4461],{"type":42,"tag":88,"props":4416,"children":4417},{},[4418,4419],{"type":48,"value":4334},{"type":42,"tag":57,"props":4420,"children":4422},{"className":4421},[],[4423],{"type":48,"value":4424},"raw.yahoo_prices",{"type":42,"tag":88,"props":4426,"children":4427},{},[4428,4429,4434,4435,4440],{"type":48,"value":4344},{"type":42,"tag":57,"props":4430,"children":4432},{"className":4431},[],[4433],{"type":48,"value":4350},{"type":48,"value":4352},{"type":42,"tag":57,"props":4436,"children":4438},{"className":4437},[],[4439],{"type":48,"value":4358},{"type":48,"value":4360},{"type":42,"tag":88,"props":4442,"children":4443},{},[4444],{"type":48,"value":4445},"Dedupe on (symbol, date)",{"type":42,"tag":88,"props":4447,"children":4448},{},[4449,4450],{"type":48,"value":4381},{"type":42,"tag":57,"props":4451,"children":4453},{"className":4452},[],[4454],{"type":48,"value":4455},"daily_return = (close - LAG(close) OVER (PARTITION BY symbol ORDER BY date)) / LAG(close) OVER (...)",{"type":42,"tag":88,"props":4457,"children":4458},{},[4459],{"type":48,"value":4460},"Compute 20-day and 50-day simple moving averages of close",{"type":42,"tag":88,"props":4462,"children":4463},{},[4464],{"type":48,"value":4465},"Keep: symbol, date, open, high, low, close, adj_close, volume, daily_return, sma_20, sma_50",{"type":42,"tag":51,"props":4467,"children":4468},{},[4469,4478,4479],{"type":42,"tag":94,"props":4470,"children":4471},{},[4472],{"type":42,"tag":57,"props":4473,"children":4475},{"className":4474},[],[4476],{"type":48,"value":4477},"staging/macro.sql",{"type":48,"value":4320},{"type":42,"tag":57,"props":4480,"children":4482},{"className":4481},[],[4483],{"type":48,"value":4484},"staging.macro",{"type":42,"tag":84,"props":4486,"children":4487},{},[4488,4497,4542,4555],{"type":42,"tag":88,"props":4489,"children":4490},{},[4491,4492],{"type":48,"value":4334},{"type":42,"tag":57,"props":4493,"children":4495},{"className":4494},[],[4496],{"type":48,"value":4030},{"type":42,"tag":88,"props":4498,"children":4499},{},[4500,4502,4508,4510,4516,4518,4524,4526,4532,4534,4540],{"type":48,"value":4501},"Pivot so each date has columns: ",{"type":42,"tag":57,"props":4503,"children":4505},{"className":4504},[],[4506],{"type":48,"value":4507},"fed_funds_rate",{"type":48,"value":4509}," (FEDFUNDS), ",{"type":42,"tag":57,"props":4511,"children":4513},{"className":4512},[],[4514],{"type":48,"value":4515},"cpi",{"type":48,"value":4517}," (CPIAUCSL), ",{"type":42,"tag":57,"props":4519,"children":4521},{"className":4520},[],[4522],{"type":48,"value":4523},"unemployment_rate",{"type":48,"value":4525}," (UNRATE), ",{"type":42,"tag":57,"props":4527,"children":4529},{"className":4528},[],[4530],{"type":48,"value":4531},"yield_spread_10y2y",{"type":48,"value":4533}," (T10Y2Y), ",{"type":42,"tag":57,"props":4535,"children":4537},{"className":4536},[],[4538],{"type":48,"value":4539},"real_gdp",{"type":48,"value":4541}," (GDPC1)",{"type":42,"tag":88,"props":4543,"children":4544},{},[4545,4547,4553],{"type":48,"value":4546},"Forward-fill missing values (monthly/quarterly series need daily granularity) using ",{"type":42,"tag":57,"props":4548,"children":4550},{"className":4549},[],[4551],{"type":48,"value":4552},"LAST_VALUE(... IGNORE NULLS) OVER (ORDER BY date)",{"type":48,"value":4554}," or equivalent",{"type":42,"tag":88,"props":4556,"children":4557},{},[4558,4560,4566,4568],{"type":48,"value":4559},"Add a ",{"type":42,"tag":57,"props":4561,"children":4563},{"className":4562},[],[4564],{"type":48,"value":4565},"regime",{"type":48,"value":4567}," column: ",{"type":42,"tag":57,"props":4569,"children":4571},{"className":4570},[],[4572],{"type":48,"value":4573},"CASE WHEN yield_spread_10y2y \u003C 0 THEN 'inverted' ELSE 'normal' END",{"type":42,"tag":51,"props":4575,"children":4576},{},[4577,4579,4585,4587,4593,4595,4601],{"type":48,"value":4578},"For each asset, add a top-level ",{"type":42,"tag":57,"props":4580,"children":4582},{"className":4581},[],[4583],{"type":48,"value":4584},"description:",{"type":48,"value":4586},", column descriptions, and at least one quality check (e.g. ",{"type":42,"tag":57,"props":4588,"children":4590},{"className":4589},[],[4591],{"type":48,"value":4592},"not_null",{"type":48,"value":4594}," on symbol/date, ",{"type":42,"tag":57,"props":4596,"children":4598},{"className":4597},[],[4599],{"type":48,"value":4600},"unique",{"type":48,"value":4602}," on the grain columns).",{"type":42,"tag":51,"props":4604,"children":4605},{},[4606],{"type":48,"value":4607},"Show me the SQL for each asset before writing the files. Don't run anything yet - I'll approve first.",{"type":42,"tag":51,"props":4609,"children":4610},{},[4611,4613,4619],{"type":48,"value":4612},"Read each SQL file the agent produces. Look specifically for the ",{"type":42,"tag":57,"props":4614,"children":4616},{"className":4615},[],[4617],{"type":48,"value":4618},"QUALIFY",{"type":48,"value":4620},", the dedup logic, and the pivot structure. If anything looks off, push back - it's cheaper to correct here than downstream.",{"type":42,"tag":43,"props":4622,"children":4624},{"id":4623},"_2-scaffold-the-reports-table",[4625],{"type":48,"value":4626},"2. Scaffold the reports table",{"type":42,"tag":51,"props":4628,"children":4629},{},[4630],{"type":48,"value":3993},{"type":42,"tag":157,"props":4632,"children":4633},{},[4634,4653,4672,4833,4867],{"type":42,"tag":51,"props":4635,"children":4636},{},[4637,4639,4644,4646,4652],{"type":48,"value":4638},"Now create one Bruin SQL asset for the reports layer, materialized as a ",{"type":42,"tag":94,"props":4640,"children":4641},{},[4642],{"type":48,"value":4643},"table",{"type":48,"value":4645}," with schema ",{"type":42,"tag":57,"props":4647,"children":4649},{"className":4648},[],[4650],{"type":48,"value":4651},"reports",{"type":48,"value":3607},{"type":42,"tag":51,"props":4654,"children":4655},{},[4656,4665,4666],{"type":42,"tag":94,"props":4657,"children":4658},{},[4659],{"type":42,"tag":57,"props":4660,"children":4662},{"className":4661},[],[4663],{"type":48,"value":4664},"reports/ticker_quarterly.sql",{"type":48,"value":4320},{"type":42,"tag":57,"props":4667,"children":4669},{"className":4668},[],[4670],{"type":48,"value":4671},"reports.ticker_quarterly",{"type":42,"tag":84,"props":4673,"children":4674},{},[4675,4680,4692,4755,4796],{"type":42,"tag":88,"props":4676,"children":4677},{},[4678],{"type":48,"value":4679},"One row per (symbol, fiscal_quarter_end)",{"type":42,"tag":88,"props":4681,"children":4682},{},[4683,4685,4690],{"type":48,"value":4684},"Join ",{"type":42,"tag":57,"props":4686,"children":4688},{"className":4687},[],[4689],{"type":48,"value":4326},{"type":48,"value":4691}," as the grain",{"type":42,"tag":88,"props":4693,"children":4694},{},[4695,4697],{"type":48,"value":4696},"Compute:\n",{"type":42,"tag":84,"props":4698,"children":4699},{},[4700,4711,4722,4733,4744],{"type":42,"tag":88,"props":4701,"children":4702},{},[4703,4709],{"type":42,"tag":57,"props":4704,"children":4706},{"className":4705},[],[4707],{"type":48,"value":4708},"ttm_revenue",{"type":48,"value":4710}," = sum of last 4 quarters of revenue (rolling window over symbol ordered by fiscal_quarter_end)",{"type":42,"tag":88,"props":4712,"children":4713},{},[4714,4720],{"type":42,"tag":57,"props":4715,"children":4717},{"className":4716},[],[4718],{"type":48,"value":4719},"ttm_fcf",{"type":48,"value":4721}," = same rolling 4-quarter sum of free_cash_flow",{"type":42,"tag":88,"props":4723,"children":4724},{},[4725,4731],{"type":42,"tag":57,"props":4726,"children":4728},{"className":4727},[],[4729],{"type":48,"value":4730},"ttm_fcf_margin",{"type":48,"value":4732}," = ttm_fcf / NULLIF(ttm_revenue, 0)",{"type":42,"tag":88,"props":4734,"children":4735},{},[4736,4742],{"type":42,"tag":57,"props":4737,"children":4739},{"className":4738},[],[4740],{"type":48,"value":4741},"revenue_yoy_growth",{"type":48,"value":4743}," = current quarter revenue / revenue 4 quarters ago - 1",{"type":42,"tag":88,"props":4745,"children":4746},{},[4747,4753],{"type":42,"tag":57,"props":4748,"children":4750},{"className":4749},[],[4751],{"type":48,"value":4752},"fcf_margin_qoq_change",{"type":48,"value":4754}," = (free_cash_flow / NULLIF(revenue, 0)) - (lag 1 quarter's fcf / revenue)",{"type":42,"tag":88,"props":4756,"children":4757},{},[4758,4759,4764,4766],{"type":48,"value":4684},{"type":42,"tag":57,"props":4760,"children":4762},{"className":4761},[],[4763],{"type":48,"value":4411},{"type":48,"value":4765}," using the next available trading day at or after the fiscal_quarter_end (fundamentals lag the quarter end - price \"as of reporting\" is approximated here)\n",{"type":42,"tag":84,"props":4767,"children":4768},{},[4769,4785],{"type":42,"tag":88,"props":4770,"children":4771},{},[4772,4778,4779],{"type":42,"tag":57,"props":4773,"children":4775},{"className":4774},[],[4776],{"type":48,"value":4777},"price_at_quarter_end",{"type":48,"value":3472},{"type":42,"tag":57,"props":4780,"children":4782},{"className":4781},[],[4783],{"type":48,"value":4784},"volume_at_quarter_end",{"type":42,"tag":88,"props":4786,"children":4787},{},[4788,4794],{"type":42,"tag":57,"props":4789,"children":4791},{"className":4790},[],[4792],{"type":48,"value":4793},"quarterly_return",{"type":48,"value":4795}," = price at this quarter end / price at previous quarter end - 1",{"type":42,"tag":88,"props":4797,"children":4798},{},[4799,4800,4805,4807],{"type":48,"value":4684},{"type":42,"tag":57,"props":4801,"children":4803},{"className":4802},[],[4804],{"type":48,"value":4484},{"type":48,"value":4806}," on the quarter_end date (backward-fill if that date has no macro row):\n",{"type":42,"tag":84,"props":4808,"children":4809},{},[4810],{"type":42,"tag":88,"props":4811,"children":4812},{},[4813,4819,4820,4826,4827],{"type":42,"tag":57,"props":4814,"children":4816},{"className":4815},[],[4817],{"type":48,"value":4818},"fed_funds_rate_at_qend",{"type":48,"value":3472},{"type":42,"tag":57,"props":4821,"children":4823},{"className":4822},[],[4824],{"type":48,"value":4825},"yield_spread_at_qend",{"type":48,"value":3472},{"type":42,"tag":57,"props":4828,"children":4830},{"className":4829},[],[4831],{"type":48,"value":4832},"regime_at_qend",{"type":42,"tag":51,"props":4834,"children":4835},{},[4836,4838,4844,4845,4851,4853,4858,4860,4865],{"type":48,"value":4837},"Add asset-level description, column descriptions, tags (",{"type":42,"tag":57,"props":4839,"children":4841},{"className":4840},[],[4842],{"type":48,"value":4843},"tier:reports",{"type":48,"value":3472},{"type":42,"tag":57,"props":4846,"children":4848},{"className":4847},[],[4849],{"type":48,"value":4850},"domain:finance",{"type":48,"value":4852},"), and quality checks (",{"type":42,"tag":57,"props":4854,"children":4856},{"className":4855},[],[4857],{"type":48,"value":4592},{"type":48,"value":4859}," on symbol + fiscal_quarter_end, ",{"type":42,"tag":57,"props":4861,"children":4863},{"className":4862},[],[4864],{"type":48,"value":4600},{"type":48,"value":4866}," on the pair).",{"type":42,"tag":51,"props":4868,"children":4869},{},[4870],{"type":48,"value":4871},"Show me the SQL before writing. I'll approve before you run anything.",{"type":42,"tag":51,"props":4873,"children":4874},{},[4875],{"type":48,"value":4876},"This is the analysis-ready table. Every question in Step 6 will start here.",{"type":42,"tag":43,"props":4878,"children":4880},{"id":4879},"_3-run-and-spot-check",[4881],{"type":48,"value":4882},"3. Run and spot-check",{"type":42,"tag":51,"props":4884,"children":4885},{},[4886],{"type":48,"value":3993},{"type":42,"tag":157,"props":4888,"children":4889},{},[4890,4909,4921,4993],{"type":42,"tag":51,"props":4891,"children":4892},{},[4893,4894,4900,4902,4907],{"type":48,"value":210},{"type":42,"tag":57,"props":4895,"children":4897},{"className":4896},[],[4898],{"type":48,"value":4899},"bruin validate stock-analyst-101/",{"type":48,"value":4901}," first. If it passes, run ",{"type":42,"tag":57,"props":4903,"children":4905},{"className":4904},[],[4906],{"type":48,"value":3960},{"type":48,"value":4908}," and stream the output. Tell me which assets succeeded and which failed.",{"type":42,"tag":51,"props":4910,"children":4911},{},[4912,4914,4920],{"type":48,"value":4913},"After it completes, do spot checks across all three layers using ",{"type":42,"tag":57,"props":4915,"children":4917},{"className":4916},[],[4918],{"type":48,"value":4919},"bruin query --connection duckdb-default",{"type":48,"value":3346},{"type":42,"tag":203,"props":4922,"children":4923},{},[4924,4949,4980],{"type":42,"tag":88,"props":4925,"children":4926},{},[4927,4929,4934,4936,4941,4942,4947],{"type":48,"value":4928},"Row counts: ",{"type":42,"tag":57,"props":4930,"children":4932},{"className":4931},[],[4933],{"type":48,"value":4023},{"type":48,"value":4935}," vs ",{"type":42,"tag":57,"props":4937,"children":4939},{"className":4938},[],[4940],{"type":48,"value":4326},{"type":48,"value":4935},{"type":42,"tag":57,"props":4943,"children":4945},{"className":4944},[],[4946],{"type":48,"value":4671},{"type":48,"value":4948}," - any unexpected drops?",{"type":42,"tag":88,"props":4950,"children":4951},{},[4952,4954,4959,4961,4966,4967,4972,4973,4978],{"type":48,"value":4953},"For one ticker (e.g. AAPL), show the last 4 rows of ",{"type":42,"tag":57,"props":4955,"children":4957},{"className":4956},[],[4958],{"type":48,"value":4671},{"type":48,"value":4960}," - do ",{"type":42,"tag":57,"props":4962,"children":4964},{"className":4963},[],[4965],{"type":48,"value":4708},{"type":48,"value":3472},{"type":42,"tag":57,"props":4968,"children":4970},{"className":4969},[],[4971],{"type":48,"value":4730},{"type":48,"value":3472},{"type":42,"tag":57,"props":4974,"children":4976},{"className":4975},[],[4977],{"type":48,"value":4832},{"type":48,"value":4979}," look sensible?",{"type":42,"tag":88,"props":4981,"children":4982},{},[4983,4985,4991],{"type":48,"value":4984},"Null audit: ",{"type":42,"tag":57,"props":4986,"children":4988},{"className":4987},[],[4989],{"type":48,"value":4990},"SELECT COUNT(*) FILTER (WHERE ttm_fcf_margin IS NULL) FROM reports.ticker_quarterly",{"type":48,"value":4992}," - some nulls expected for early quarters (can't compute TTM without 4 prior quarters); flag if too many.",{"type":42,"tag":51,"props":4994,"children":4995},{},[4996],{"type":48,"value":4997},"Show me the results before moving on.",{"type":42,"tag":51,"props":4999,"children":5000},{},[5001],{"type":48,"value":5002},"You should see ~4–8 quarters per ticker in the final table, depending on how much fundamentals history FMP returned.",{"type":42,"tag":43,"props":5004,"children":5006},{"id":5005},"_4-why-the-layering-matters",[5007],{"type":48,"value":5008},"4. Why the layering matters",{"type":42,"tag":51,"props":5010,"children":5011},{},[5012],{"type":48,"value":5013},"Now you have a clean three-tier pipeline:",{"type":42,"tag":258,"props":5015,"children":5018},{"className":5016,"code":5017,"language":48},[261],"raw.*                      staging.*                   reports.*\n──────────────────         ──────────────────          ──────────────────\nfmp_fundamentals    →      fundamentals        ┐\nyahoo_prices        →      prices              ├──→   ticker_quarterly\nfred_macro          →      macro               ┘\n(source truth)             (cleaned + typed)           (analysis-ready)\n",[5019],{"type":42,"tag":57,"props":5020,"children":5021},{"__ignoreMap":7},[5022],{"type":48,"value":5017},{"type":42,"tag":51,"props":5024,"children":5025},{},[5026,5028,5036],{"type":48,"value":5027},"Every question you ask in Step 6 goes against ",{"type":42,"tag":94,"props":5029,"children":5030},{},[5031],{"type":42,"tag":57,"props":5032,"children":5034},{"className":5033},[],[5035],{"type":48,"value":4671},{"type":48,"value":5037}," first. The AI agent doesn't have to re-derive TTM FCF margin or re-align fundamentals-to-prices every time. Raw and staging exist for validation and troubleshooting, not for everyday analysis.",{"type":42,"tag":51,"props":5039,"children":5040},{},[5041,5043,5048,5050,5055],{"type":48,"value":5042},"In the next step, you'll enhance each layer with column-level descriptions and update your pipeline-scoped ",{"type":42,"tag":57,"props":5044,"children":5046},{"className":5045},[],[5047],{"type":48,"value":69},{"type":48,"value":5049}," so the agent knows to default to ",{"type":42,"tag":57,"props":5051,"children":5053},{"className":5052},[],[5054],{"type":48,"value":4196},{"type":48,"value":3607},{"type":42,"tag":43,"props":5057,"children":5058},{"id":998},[5059],{"type":48,"value":1001},{"type":42,"tag":51,"props":5061,"children":5062},{},[5063],{"type":48,"value":5064},"You built a proper layered pipeline - raw → staging → reports - without writing any SQL by hand. The agent wrote every asset, you validated the logic, Bruin ran the whole pipeline. Your data is now cleaned, typed, deduped, joined, and enriched with the metrics an analyst actually wants. Next step: make sure the AI knows which layer to query when.",{"title":7,"searchDepth":18,"depth":18,"links":5066},[5067,5068,5069,5070,5071,5072,5073],{"id":45,"depth":18,"text":49},{"id":74,"depth":18,"text":77},{"id":4271,"depth":18,"text":4274},{"id":4623,"depth":18,"text":4626},{"id":4879,"depth":18,"text":4882},{"id":5005,"depth":18,"text":5008},{"id":998,"depth":18,"text":1001},"content:tutorials:stock-analyst-101:transform-reports.md","tutorials/stock-analyst-101/transform-reports.md","tutorials/stock-analyst-101/transform-reports",{"_path":5078,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":5079,"description":5080,"date":10,"readingTime":601,"category":12,"tags":5081,"difficulty":17,"module":5,"step":11,"journeys":5082,"roles":5083,"learnMore":5084,"author":5091,"body":5092,"_type":519,"_id":6185,"_source":1032,"_file":6186,"_stem":6187,"_extension":1035},"/tutorials/stock-analyst-101/enhance-context","Teach the AI Your Domain","Use bruin ai enhance to document every column, then add a pipeline-scoped AGENTS.md with finance context so the agent reasons about your data like a real analyst.",[14,15,1831,16,22],[20],[22,23],[5085,5088],{"label":5086,"url":5087},"bruin ai enhance reference","https://getbruin.com/docs/bruin/commands/ai-enhance.html",{"label":5089,"url":5090},"Bruin MCP best practices","https://getbruin.com/docs/bruin/getting-started/bruin-mcp.html#best-practices-for-ai-agents",{"name":35,"role":36,"image":37},{"type":39,"children":5093,"toc":6177},[5094,5098,5136,5140,5153,5158,5219,5231,5237,5241,5290,5310,5496,5501,5509,5515,5554,5558,6080,6099,6105,6116,6124,6150,6154,6173],{"type":42,"tag":43,"props":5095,"children":5096},{"id":45},[5097],{"type":48,"value":49},{"type":42,"tag":203,"props":5099,"children":5100},{},[5101,5113],{"type":42,"tag":88,"props":5102,"children":5103},{},[5104,5105,5111],{"type":48,"value":210},{"type":42,"tag":57,"props":5106,"children":5108},{"className":5107},[],[5109],{"type":48,"value":5110},"bruin ai enhance",{"type":48,"value":5112}," so the agent auto-documents every table and column",{"type":42,"tag":88,"props":5114,"children":5115},{},[5116,5118,5128,5129,5134],{"type":48,"value":5117},"Create a ",{"type":42,"tag":94,"props":5119,"children":5120},{},[5121,5123],{"type":48,"value":5122},"pipeline-specific ",{"type":42,"tag":57,"props":5124,"children":5126},{"className":5125},[],[5127],{"type":48,"value":69},{"type":48,"value":987},{"type":42,"tag":57,"props":5130,"children":5132},{"className":5131},[],[5133],{"type":48,"value":993},{"type":48,"value":5135}," folder with finance-specific domain knowledge, acronyms, and query guidelines",{"type":42,"tag":43,"props":5137,"children":5138},{"id":74},[5139],{"type":48,"value":77},{"type":42,"tag":51,"props":5141,"children":5142},{},[5143,5145,5151],{"type":48,"value":5144},"Data alone is not enough. An AI agent looking at a column called ",{"type":42,"tag":57,"props":5146,"children":5148},{"className":5147},[],[5149],{"type":48,"value":5150},"fcf",{"type":48,"value":5152}," will guess \"something cash flow related\" - fine for casual questions, wrong for serious analysis (is it free cash flow? operating cash flow? levered or unlevered? annual or TTM?). Your job in this step is to make sure the agent never has to guess.",{"type":42,"tag":51,"props":5154,"children":5155},{},[5156],{"type":48,"value":5157},"You're giving the agent three layers of context now:",{"type":42,"tag":84,"props":5159,"children":5160},{},[5161,5178,5194],{"type":42,"tag":88,"props":5162,"children":5163},{},[5164,5169,5171,5176],{"type":42,"tag":94,"props":5165,"children":5166},{},[5167],{"type":48,"value":5168},"Workspace-level rules",{"type":48,"value":5170}," - the root ",{"type":42,"tag":57,"props":5172,"children":5174},{"className":5173},[],[5175],{"type":48,"value":69},{"type":48,"value":5177}," from Step 2 tells the agent how to work with Bruin (CLI, validate, test limits, etc.) across any pipeline in this workspace.",{"type":42,"tag":88,"props":5179,"children":5180},{},[5181,5186,5188,5193],{"type":42,"tag":94,"props":5182,"children":5183},{},[5184],{"type":48,"value":5185},"Schema context",{"type":48,"value":5187}," - what each table and column is. Auto-generated in seconds with ",{"type":42,"tag":57,"props":5189,"children":5191},{"className":5190},[],[5192],{"type":48,"value":5110},{"type":48,"value":3607},{"type":42,"tag":88,"props":5195,"children":5196},{},[5197,5202,5204,5209,5211,5217],{"type":42,"tag":94,"props":5198,"children":5199},{},[5200],{"type":48,"value":5201},"Pipeline-specific domain context",{"type":48,"value":5203}," - how a stock analyst thinks about ",{"type":42,"tag":450,"props":5205,"children":5206},{},[5207],{"type":48,"value":5208},"this",{"type":48,"value":5210}," pipeline's data. Lives next to the pipeline as ",{"type":42,"tag":57,"props":5212,"children":5214},{"className":5213},[],[5215],{"type":48,"value":5216},"stock-analyst-101/AGENTS.md",{"type":48,"value":5218}," so it travels with it and doesn't leak into other pipelines.",{"type":42,"tag":51,"props":5220,"children":5221},{},[5222,5224,5229],{"type":48,"value":5223},"AI coding tools (Claude Code, Cursor, Codex) read nested ",{"type":42,"tag":57,"props":5225,"children":5227},{"className":5226},[],[5228],{"type":48,"value":69},{"type":48,"value":5230}," files when they work inside that subfolder, so the pipeline-scoped file automatically layers on top of the workspace-level one. Together these turn the agent from \"eager intern\" into \"actual analyst.\"",{"type":42,"tag":43,"props":5232,"children":5234},{"id":5233},"_1-auto-enhance-schema-context",[5235],{"type":48,"value":5236},"1. Auto-enhance schema context",{"type":42,"tag":51,"props":5238,"children":5239},{},[5240],{"type":48,"value":3993},{"type":42,"tag":157,"props":5242,"children":5243},{},[5244],{"type":42,"tag":51,"props":5245,"children":5246},{},[5247,5248,5254,5256,5261,5262,5267,5269,5274,5276,5281,5283,5288],{"type":48,"value":210},{"type":42,"tag":57,"props":5249,"children":5251},{"className":5250},[],[5252],{"type":48,"value":5253},"bruin ai enhance stock-analyst-101/",{"type":48,"value":5255}," and let me know when it's done. It should enhance assets across all three layers - ",{"type":42,"tag":57,"props":5257,"children":5259},{"className":5258},[],[5260],{"type":48,"value":3973},{"type":48,"value":3472},{"type":42,"tag":57,"props":5263,"children":5265},{"className":5264},[],[5266],{"type":48,"value":4180},{"type":48,"value":5268},", and ",{"type":42,"tag":57,"props":5270,"children":5272},{"className":5271},[],[5273],{"type":48,"value":4196},{"type":48,"value":5275},". Then show me the changes it made to ",{"type":42,"tag":57,"props":5277,"children":5279},{"className":5278},[],[5280],{"type":48,"value":3574},{"type":48,"value":5282}," (raw) and ",{"type":42,"tag":57,"props":5284,"children":5286},{"className":5285},[],[5287],{"type":48,"value":4664},{"type":48,"value":5289}," (reports) so I can spot-check the descriptions.",{"type":42,"tag":51,"props":5291,"children":5292},{},[5293,5295,5300,5302,5308],{"type":48,"value":5294},"This command looks at each table, asks an LLM to describe what it sees, and writes column descriptions directly into the asset YAML - across all three layers. After it runs, your ",{"type":42,"tag":57,"props":5296,"children":5298},{"className":5297},[],[5299],{"type":48,"value":3574},{"type":48,"value":5301}," will have a ",{"type":42,"tag":57,"props":5303,"children":5305},{"className":5304},[],[5306],{"type":48,"value":5307},"columns:",{"type":48,"value":5309}," block like:",{"type":42,"tag":258,"props":5311,"children":5313},{"className":314,"code":5312,"language":316,"meta":7,"style":7},"columns:\n  - name: symbol\n    type: varchar\n    description: \"Stock ticker symbol (e.g. AAPL)\"\n  - name: date\n    type: date\n    description: \"Fiscal period end date, not calendar quarter\"\n  - name: revenue\n    type: bigint\n    description: \"Total revenue in USD for the fiscal quarter\"\n  # ...many more\n",[5314],{"type":42,"tag":57,"props":5315,"children":5316},{"__ignoreMap":7},[5317,5329,5350,5367,5384,5404,5419,5435,5455,5471,5487],{"type":42,"tag":322,"props":5318,"children":5319},{"class":324,"line":325},[5320,5325],{"type":42,"tag":322,"props":5321,"children":5322},{"style":329},[5323],{"type":48,"value":5324},"columns",{"type":42,"tag":322,"props":5326,"children":5327},{"style":335},[5328],{"type":48,"value":338},{"type":42,"tag":322,"props":5330,"children":5331},{"class":324,"line":18},[5332,5337,5341,5345],{"type":42,"tag":322,"props":5333,"children":5334},{"style":335},[5335],{"type":48,"value":5336},"  - ",{"type":42,"tag":322,"props":5338,"children":5339},{"style":329},[5340],{"type":48,"value":389},{"type":42,"tag":322,"props":5342,"children":5343},{"style":335},[5344],{"type":48,"value":394},{"type":42,"tag":322,"props":5346,"children":5347},{"style":397},[5348],{"type":48,"value":5349},"symbol\n",{"type":42,"tag":322,"props":5351,"children":5352},{"class":324,"line":353},[5353,5358,5362],{"type":42,"tag":322,"props":5354,"children":5355},{"style":329},[5356],{"type":48,"value":5357},"    type",{"type":42,"tag":322,"props":5359,"children":5360},{"style":335},[5361],{"type":48,"value":394},{"type":42,"tag":322,"props":5363,"children":5364},{"style":397},[5365],{"type":48,"value":5366},"varchar\n",{"type":42,"tag":322,"props":5368,"children":5369},{"class":324,"line":366},[5370,5375,5379],{"type":42,"tag":322,"props":5371,"children":5372},{"style":329},[5373],{"type":48,"value":5374},"    description",{"type":42,"tag":322,"props":5376,"children":5377},{"style":335},[5378],{"type":48,"value":394},{"type":42,"tag":322,"props":5380,"children":5381},{"style":397},[5382],{"type":48,"value":5383},"\"Stock ticker symbol (e.g. AAPL)\"\n",{"type":42,"tag":322,"props":5385,"children":5386},{"class":324,"line":11},[5387,5391,5395,5399],{"type":42,"tag":322,"props":5388,"children":5389},{"style":335},[5390],{"type":48,"value":5336},{"type":42,"tag":322,"props":5392,"children":5393},{"style":329},[5394],{"type":48,"value":389},{"type":42,"tag":322,"props":5396,"children":5397},{"style":335},[5398],{"type":48,"value":394},{"type":42,"tag":322,"props":5400,"children":5401},{"style":397},[5402],{"type":48,"value":5403},"date\n",{"type":42,"tag":322,"props":5405,"children":5406},{"class":324,"line":403},[5407,5411,5415],{"type":42,"tag":322,"props":5408,"children":5409},{"style":329},[5410],{"type":48,"value":5357},{"type":42,"tag":322,"props":5412,"children":5413},{"style":335},[5414],{"type":48,"value":394},{"type":42,"tag":322,"props":5416,"children":5417},{"style":397},[5418],{"type":48,"value":5403},{"type":42,"tag":322,"props":5420,"children":5421},{"class":324,"line":574},[5422,5426,5430],{"type":42,"tag":322,"props":5423,"children":5424},{"style":329},[5425],{"type":48,"value":5374},{"type":42,"tag":322,"props":5427,"children":5428},{"style":335},[5429],{"type":48,"value":394},{"type":42,"tag":322,"props":5431,"children":5432},{"style":397},[5433],{"type":48,"value":5434},"\"Fiscal period end date, not calendar quarter\"\n",{"type":42,"tag":322,"props":5436,"children":5437},{"class":324,"line":583},[5438,5442,5446,5450],{"type":42,"tag":322,"props":5439,"children":5440},{"style":335},[5441],{"type":48,"value":5336},{"type":42,"tag":322,"props":5443,"children":5444},{"style":329},[5445],{"type":48,"value":389},{"type":42,"tag":322,"props":5447,"children":5448},{"style":335},[5449],{"type":48,"value":394},{"type":42,"tag":322,"props":5451,"children":5452},{"style":397},[5453],{"type":48,"value":5454},"revenue\n",{"type":42,"tag":322,"props":5456,"children":5457},{"class":324,"line":592},[5458,5462,5466],{"type":42,"tag":322,"props":5459,"children":5460},{"style":329},[5461],{"type":48,"value":5357},{"type":42,"tag":322,"props":5463,"children":5464},{"style":335},[5465],{"type":48,"value":394},{"type":42,"tag":322,"props":5467,"children":5468},{"style":397},[5469],{"type":48,"value":5470},"bigint\n",{"type":42,"tag":322,"props":5472,"children":5473},{"class":324,"line":601},[5474,5478,5482],{"type":42,"tag":322,"props":5475,"children":5476},{"style":329},[5477],{"type":48,"value":5374},{"type":42,"tag":322,"props":5479,"children":5480},{"style":335},[5481],{"type":48,"value":394},{"type":42,"tag":322,"props":5483,"children":5484},{"style":397},[5485],{"type":48,"value":5486},"\"Total revenue in USD for the fiscal quarter\"\n",{"type":42,"tag":322,"props":5488,"children":5489},{"class":324,"line":609},[5490],{"type":42,"tag":322,"props":5491,"children":5493},{"style":5492},"--shiki-default:#6A737D",[5494],{"type":48,"value":5495},"  # ...many more\n",{"type":42,"tag":51,"props":5497,"children":5498},{},[5499],{"type":48,"value":5500},"These descriptions become part of the MCP context the agent reads before every query. You don't need to memorize any of this - the agent will look it up when it needs to.",{"type":42,"tag":2058,"props":5502,"children":5503},{},[5504],{"type":42,"tag":51,"props":5505,"children":5506},{},[5507],{"type":48,"value":5508},"If the agent got a description wrong (e.g. it misread what a column means), just ask it to fix that specific line. The YAML is yours to edit.",{"type":42,"tag":43,"props":5510,"children":5512},{"id":5511},"_2-create-a-pipeline-specific-agentsmd",[5513],{"type":48,"value":5514},"2. Create a pipeline-specific AGENTS.md",{"type":42,"tag":51,"props":5516,"children":5517},{},[5518,5520,5525,5527,5532,5534,5539,5541,5546,5547,5552],{"type":48,"value":5519},"The root ",{"type":42,"tag":57,"props":5521,"children":5523},{"className":5522},[],[5524],{"type":48,"value":69},{"type":48,"value":5526}," you seeded in Step 2 covers ",{"type":42,"tag":450,"props":5528,"children":5529},{},[5530],{"type":48,"value":5531},"how",{"type":48,"value":5533}," the agent should work with Bruin in general. This new file covers ",{"type":42,"tag":450,"props":5535,"children":5536},{},[5537],{"type":48,"value":5538},"what",{"type":48,"value":5540}," this specific pipeline's data means. It lives ",{"type":42,"tag":94,"props":5542,"children":5543},{},[5544],{"type":48,"value":5545},"inside the pipeline folder",{"type":48,"value":100},{"type":42,"tag":57,"props":5548,"children":5550},{"className":5549},[],[5551],{"type":48,"value":5216},{"type":48,"value":5553},") so the finance-specific context stays scoped to the pipeline it belongs to - if you later add a different pipeline in the same workspace, you won't pollute it with finance glossary entries.",{"type":42,"tag":51,"props":5555,"children":5556},{},[5557],{"type":48,"value":461},{"type":42,"tag":157,"props":5559,"children":5560},{},[5561,5587],{"type":42,"tag":51,"props":5562,"children":5563},{},[5564,5566,5571,5573,5578,5580,5585],{"type":48,"value":5565},"Create a new file at ",{"type":42,"tag":57,"props":5567,"children":5569},{"className":5568},[],[5570],{"type":48,"value":5216},{"type":48,"value":5572}," (inside the pipeline folder - ",{"type":42,"tag":94,"props":5574,"children":5575},{},[5576],{"type":48,"value":5577},"not",{"type":48,"value":5579}," the workspace root) with the content below. Do not modify the root ",{"type":42,"tag":57,"props":5581,"children":5583},{"className":5582},[],[5584],{"type":48,"value":69},{"type":48,"value":5586},"; the pipeline-specific file layers on top of it automatically when the agent works inside the pipeline folder. After you're done, show me the file.",{"type":42,"tag":258,"props":5588,"children":5590},{"className":517,"code":5589,"language":519,"meta":7,"style":7},"# AGENTS.md - stock-analyst-101\n\n## Pipeline overview\nThis is a stock-analyst research pipeline. Data lives in DuckDB\n(`./stock-analyst-101/stock.duckdb`), organized in three layers:\n\n**Raw layer** (`raw.*`) - unmodified from source:\n- `raw.fmp_fundamentals` - quarterly income statement, balance sheet, cash flow per ticker (from FMP)\n- `raw.yahoo_prices` - daily OHLCV stock prices per ticker (from Yahoo Finance)\n- `raw.fred_macro` - US macroeconomic time series (from FRED)\n\n**Staging layer** (`staging.*`) - cleaned, typed, deduplicated:\n- `staging.fundamentals` - pivoted fundamentals, one row per (symbol, fiscal_quarter_end), includes `free_cash_flow`\n- `staging.prices` - cleaned daily prices with `daily_return`, `sma_20`, `sma_50`\n- `staging.macro` - pivoted FRED series, forward-filled, with a `regime` column ('inverted' | 'normal')\n\n**Reports layer** (`reports.*`) - analysis-ready, joined, pre-computed metrics:\n- `reports.ticker_quarterly` - one row per (symbol, fiscal_quarter_end) with TTM revenue/FCF/FCF margin, QoQ + YoY growth, quarterly price return, and the macro regime at quarter end\n\nThe DuckDB connection name is `duckdb-default`.\n\n## Layer usage rules (IMPORTANT)\n**Default to `reports.*` for all analysis.** It's pre-cleaned, pre-joined, and contains the metrics an analyst typically wants.\n\nOnly drop to lower layers with an explicit reason:\n- **`staging.*`** - when reports doesn't surface a column you need (e.g. operating margin, EPS), or when validating a transform\n- **`raw.*`** - for **data validation** (is the source complete?), **troubleshooting** (where did a wrong number come from?), or when you genuinely need a column that hasn't been promoted upstream yet\n\nWhen you do drop down, **say so in your response**: \"I'm using `staging.fundamentals` here because `reports.ticker_quarterly` doesn't expose operating margin.\" This keeps the user aware of which surface you're querying.\n\n## Domain glossary (finance)\n- **FCF** - Free Cash Flow: operating cash flow minus capital expenditures\n- **FCF margin** - FCF divided by revenue, expressed as a percentage\n- **EPS** - Earnings Per Share (diluted unless otherwise stated)\n- **P/E** - Price-to-Earnings ratio (trailing 12 months)\n- **EBITDA** - Earnings Before Interest, Taxes, Depreciation, Amortization\n- **TTM** - Trailing Twelve Months (sum of last 4 quarters)\n- **YoY / QoQ** - Year-over-Year / Quarter-over-Quarter comparisons\n- **Market cap** - shares outstanding × last closing price\n- **Yield curve inversion** - when `T10Y2Y` (10Y–2Y Treasury spread) is negative\n- **Real GDP growth** - QoQ change in `GDPC1`, annualized\n\n## FRED series reference\n- `FEDFUNDS` - Effective Fed Funds Rate (monthly, %)\n- `CPIAUCSL` - CPI All Urban Consumers (monthly, index 1982-84=100). YoY change = inflation.\n- `UNRATE` - Unemployment rate (monthly, %)\n- `T10Y2Y` - 10Y minus 2Y Treasury yield spread (daily, %). Negative = inversion.\n- `GDPC1` - Real GDP (quarterly, billions of chained 2017 dollars)\n\n## Data caveats\n- All dates are UTC. FMP dates are fiscal quarter end (may not match calendar quarter)\n- `raw.fmp_fundamentals.date` is the fiscal period end, not filing date - there's typically a 30–60 day lag between period end and when the numbers are reported\n- `raw.yahoo_prices.close` is adjusted for splits and dividends; `raw.yahoo_prices.open` is not\n- `raw.fred_macro` series have different frequencies (daily / monthly / quarterly). When joining to prices, align on the price date and use the most recent macro value (`last_value ignore nulls over ...` or a backward-looking window)\n\n## Query guidelines\n- For all analytical questions, start with `reports.ticker_quarterly`. Most questions are a SELECT against this table with a WHERE on `regime_at_qend` or a comparison across symbols.\n- When comparing fundamentals across time, prefer the pre-computed `ttm_*` columns over recomputing TTM from `staging.fundamentals`\n- If you need price detail beyond `quarterly_return` and `price_at_quarter_end`, drop to `staging.prices` and join on (symbol, date) - but always filter by date range first; the table has years of daily data per ticker\n- To get latest fundamentals per ticker from staging: `QUALIFY ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY fiscal_quarter_end DESC) = 1`\n- Never join `staging.fundamentals` directly to `staging.prices` on date - their grains differ. Use `reports.ticker_quarterly` (already aligned) or align fundamentals to the next available price date.\n",[5591],{"type":42,"tag":57,"props":5592,"children":5593},{"__ignoreMap":7},[5594,5602,5609,5617,5625,5633,5640,5648,5656,5664,5672,5679,5687,5695,5703,5711,5718,5726,5734,5741,5749,5756,5764,5772,5779,5787,5795,5803,5810,5818,5825,5833,5841,5849,5857,5865,5873,5881,5889,5897,5905,5913,5920,5928,5936,5944,5952,5960,5968,5975,5983,5991,6000,6009,6018,6026,6035,6044,6053,6062,6071],{"type":42,"tag":322,"props":5595,"children":5596},{"class":324,"line":325},[5597],{"type":42,"tag":322,"props":5598,"children":5599},{},[5600],{"type":48,"value":5601},"# AGENTS.md - stock-analyst-101\n",{"type":42,"tag":322,"props":5603,"children":5604},{"class":324,"line":18},[5605],{"type":42,"tag":322,"props":5606,"children":5607},{"emptyLinePlaceholder":537},[5608],{"type":48,"value":540},{"type":42,"tag":322,"props":5610,"children":5611},{"class":324,"line":353},[5612],{"type":42,"tag":322,"props":5613,"children":5614},{},[5615],{"type":48,"value":5616},"## Pipeline overview\n",{"type":42,"tag":322,"props":5618,"children":5619},{"class":324,"line":366},[5620],{"type":42,"tag":322,"props":5621,"children":5622},{},[5623],{"type":48,"value":5624},"This is a stock-analyst research pipeline. Data lives in DuckDB\n",{"type":42,"tag":322,"props":5626,"children":5627},{"class":324,"line":11},[5628],{"type":42,"tag":322,"props":5629,"children":5630},{},[5631],{"type":48,"value":5632},"(`./stock-analyst-101/stock.duckdb`), organized in three layers:\n",{"type":42,"tag":322,"props":5634,"children":5635},{"class":324,"line":403},[5636],{"type":42,"tag":322,"props":5637,"children":5638},{"emptyLinePlaceholder":537},[5639],{"type":48,"value":540},{"type":42,"tag":322,"props":5641,"children":5642},{"class":324,"line":574},[5643],{"type":42,"tag":322,"props":5644,"children":5645},{},[5646],{"type":48,"value":5647},"**Raw layer** (`raw.*`) - unmodified from source:\n",{"type":42,"tag":322,"props":5649,"children":5650},{"class":324,"line":583},[5651],{"type":42,"tag":322,"props":5652,"children":5653},{},[5654],{"type":48,"value":5655},"- `raw.fmp_fundamentals` - quarterly income statement, balance sheet, cash flow per ticker (from FMP)\n",{"type":42,"tag":322,"props":5657,"children":5658},{"class":324,"line":592},[5659],{"type":42,"tag":322,"props":5660,"children":5661},{},[5662],{"type":48,"value":5663},"- `raw.yahoo_prices` - daily OHLCV stock prices per ticker (from Yahoo Finance)\n",{"type":42,"tag":322,"props":5665,"children":5666},{"class":324,"line":601},[5667],{"type":42,"tag":322,"props":5668,"children":5669},{},[5670],{"type":48,"value":5671},"- `raw.fred_macro` - US macroeconomic time series (from FRED)\n",{"type":42,"tag":322,"props":5673,"children":5674},{"class":324,"line":609},[5675],{"type":42,"tag":322,"props":5676,"children":5677},{"emptyLinePlaceholder":537},[5678],{"type":48,"value":540},{"type":42,"tag":322,"props":5680,"children":5681},{"class":324,"line":618},[5682],{"type":42,"tag":322,"props":5683,"children":5684},{},[5685],{"type":48,"value":5686},"**Staging layer** (`staging.*`) - cleaned, typed, deduplicated:\n",{"type":42,"tag":322,"props":5688,"children":5689},{"class":324,"line":627},[5690],{"type":42,"tag":322,"props":5691,"children":5692},{},[5693],{"type":48,"value":5694},"- `staging.fundamentals` - pivoted fundamentals, one row per (symbol, fiscal_quarter_end), includes `free_cash_flow`\n",{"type":42,"tag":322,"props":5696,"children":5697},{"class":324,"line":636},[5698],{"type":42,"tag":322,"props":5699,"children":5700},{},[5701],{"type":48,"value":5702},"- `staging.prices` - cleaned daily prices with `daily_return`, `sma_20`, `sma_50`\n",{"type":42,"tag":322,"props":5704,"children":5705},{"class":324,"line":645},[5706],{"type":42,"tag":322,"props":5707,"children":5708},{},[5709],{"type":48,"value":5710},"- `staging.macro` - pivoted FRED series, forward-filled, with a `regime` column ('inverted' | 'normal')\n",{"type":42,"tag":322,"props":5712,"children":5713},{"class":324,"line":653},[5714],{"type":42,"tag":322,"props":5715,"children":5716},{"emptyLinePlaceholder":537},[5717],{"type":48,"value":540},{"type":42,"tag":322,"props":5719,"children":5720},{"class":324,"line":662},[5721],{"type":42,"tag":322,"props":5722,"children":5723},{},[5724],{"type":48,"value":5725},"**Reports layer** (`reports.*`) - analysis-ready, joined, pre-computed metrics:\n",{"type":42,"tag":322,"props":5727,"children":5728},{"class":324,"line":671},[5729],{"type":42,"tag":322,"props":5730,"children":5731},{},[5732],{"type":48,"value":5733},"- `reports.ticker_quarterly` - one row per (symbol, fiscal_quarter_end) with TTM revenue/FCF/FCF margin, QoQ + YoY growth, quarterly price return, and the macro regime at quarter end\n",{"type":42,"tag":322,"props":5735,"children":5736},{"class":324,"line":680},[5737],{"type":42,"tag":322,"props":5738,"children":5739},{"emptyLinePlaceholder":537},[5740],{"type":48,"value":540},{"type":42,"tag":322,"props":5742,"children":5743},{"class":324,"line":689},[5744],{"type":42,"tag":322,"props":5745,"children":5746},{},[5747],{"type":48,"value":5748},"The DuckDB connection name is `duckdb-default`.\n",{"type":42,"tag":322,"props":5750,"children":5751},{"class":324,"line":697},[5752],{"type":42,"tag":322,"props":5753,"children":5754},{"emptyLinePlaceholder":537},[5755],{"type":48,"value":540},{"type":42,"tag":322,"props":5757,"children":5758},{"class":324,"line":706},[5759],{"type":42,"tag":322,"props":5760,"children":5761},{},[5762],{"type":48,"value":5763},"## Layer usage rules (IMPORTANT)\n",{"type":42,"tag":322,"props":5765,"children":5766},{"class":324,"line":715},[5767],{"type":42,"tag":322,"props":5768,"children":5769},{},[5770],{"type":48,"value":5771},"**Default to `reports.*` for all analysis.** It's pre-cleaned, pre-joined, and contains the metrics an analyst typically wants.\n",{"type":42,"tag":322,"props":5773,"children":5774},{"class":324,"line":724},[5775],{"type":42,"tag":322,"props":5776,"children":5777},{"emptyLinePlaceholder":537},[5778],{"type":48,"value":540},{"type":42,"tag":322,"props":5780,"children":5781},{"class":324,"line":733},[5782],{"type":42,"tag":322,"props":5783,"children":5784},{},[5785],{"type":48,"value":5786},"Only drop to lower layers with an explicit reason:\n",{"type":42,"tag":322,"props":5788,"children":5789},{"class":324,"line":741},[5790],{"type":42,"tag":322,"props":5791,"children":5792},{},[5793],{"type":48,"value":5794},"- **`staging.*`** - when reports doesn't surface a column you need (e.g. operating margin, EPS), or when validating a transform\n",{"type":42,"tag":322,"props":5796,"children":5797},{"class":324,"line":750},[5798],{"type":42,"tag":322,"props":5799,"children":5800},{},[5801],{"type":48,"value":5802},"- **`raw.*`** - for **data validation** (is the source complete?), **troubleshooting** (where did a wrong number come from?), or when you genuinely need a column that hasn't been promoted upstream yet\n",{"type":42,"tag":322,"props":5804,"children":5805},{"class":324,"line":759},[5806],{"type":42,"tag":322,"props":5807,"children":5808},{"emptyLinePlaceholder":537},[5809],{"type":48,"value":540},{"type":42,"tag":322,"props":5811,"children":5812},{"class":324,"line":768},[5813],{"type":42,"tag":322,"props":5814,"children":5815},{},[5816],{"type":48,"value":5817},"When you do drop down, **say so in your response**: \"I'm using `staging.fundamentals` here because `reports.ticker_quarterly` doesn't expose operating margin.\" This keeps the user aware of which surface you're querying.\n",{"type":42,"tag":322,"props":5819,"children":5820},{"class":324,"line":777},[5821],{"type":42,"tag":322,"props":5822,"children":5823},{"emptyLinePlaceholder":537},[5824],{"type":48,"value":540},{"type":42,"tag":322,"props":5826,"children":5827},{"class":324,"line":786},[5828],{"type":42,"tag":322,"props":5829,"children":5830},{},[5831],{"type":48,"value":5832},"## Domain glossary (finance)\n",{"type":42,"tag":322,"props":5834,"children":5835},{"class":324,"line":795},[5836],{"type":42,"tag":322,"props":5837,"children":5838},{},[5839],{"type":48,"value":5840},"- **FCF** - Free Cash Flow: operating cash flow minus capital expenditures\n",{"type":42,"tag":322,"props":5842,"children":5843},{"class":324,"line":804},[5844],{"type":42,"tag":322,"props":5845,"children":5846},{},[5847],{"type":48,"value":5848},"- **FCF margin** - FCF divided by revenue, expressed as a percentage\n",{"type":42,"tag":322,"props":5850,"children":5851},{"class":324,"line":812},[5852],{"type":42,"tag":322,"props":5853,"children":5854},{},[5855],{"type":48,"value":5856},"- **EPS** - Earnings Per Share (diluted unless otherwise stated)\n",{"type":42,"tag":322,"props":5858,"children":5859},{"class":324,"line":821},[5860],{"type":42,"tag":322,"props":5861,"children":5862},{},[5863],{"type":48,"value":5864},"- **P/E** - Price-to-Earnings ratio (trailing 12 months)\n",{"type":42,"tag":322,"props":5866,"children":5867},{"class":324,"line":830},[5868],{"type":42,"tag":322,"props":5869,"children":5870},{},[5871],{"type":48,"value":5872},"- **EBITDA** - Earnings Before Interest, Taxes, Depreciation, Amortization\n",{"type":42,"tag":322,"props":5874,"children":5875},{"class":324,"line":838},[5876],{"type":42,"tag":322,"props":5877,"children":5878},{},[5879],{"type":48,"value":5880},"- **TTM** - Trailing Twelve Months (sum of last 4 quarters)\n",{"type":42,"tag":322,"props":5882,"children":5883},{"class":324,"line":847},[5884],{"type":42,"tag":322,"props":5885,"children":5886},{},[5887],{"type":48,"value":5888},"- **YoY / QoQ** - Year-over-Year / Quarter-over-Quarter comparisons\n",{"type":42,"tag":322,"props":5890,"children":5891},{"class":324,"line":856},[5892],{"type":42,"tag":322,"props":5893,"children":5894},{},[5895],{"type":48,"value":5896},"- **Market cap** - shares outstanding × last closing price\n",{"type":42,"tag":322,"props":5898,"children":5899},{"class":324,"line":865},[5900],{"type":42,"tag":322,"props":5901,"children":5902},{},[5903],{"type":48,"value":5904},"- **Yield curve inversion** - when `T10Y2Y` (10Y–2Y Treasury spread) is negative\n",{"type":42,"tag":322,"props":5906,"children":5907},{"class":324,"line":874},[5908],{"type":42,"tag":322,"props":5909,"children":5910},{},[5911],{"type":48,"value":5912},"- **Real GDP growth** - QoQ change in `GDPC1`, annualized\n",{"type":42,"tag":322,"props":5914,"children":5915},{"class":324,"line":883},[5916],{"type":42,"tag":322,"props":5917,"children":5918},{"emptyLinePlaceholder":537},[5919],{"type":48,"value":540},{"type":42,"tag":322,"props":5921,"children":5922},{"class":324,"line":891},[5923],{"type":42,"tag":322,"props":5924,"children":5925},{},[5926],{"type":48,"value":5927},"## FRED series reference\n",{"type":42,"tag":322,"props":5929,"children":5930},{"class":324,"line":900},[5931],{"type":42,"tag":322,"props":5932,"children":5933},{},[5934],{"type":48,"value":5935},"- `FEDFUNDS` - Effective Fed Funds Rate (monthly, %)\n",{"type":42,"tag":322,"props":5937,"children":5938},{"class":324,"line":909},[5939],{"type":42,"tag":322,"props":5940,"children":5941},{},[5942],{"type":48,"value":5943},"- `CPIAUCSL` - CPI All Urban Consumers (monthly, index 1982-84=100). YoY change = inflation.\n",{"type":42,"tag":322,"props":5945,"children":5946},{"class":324,"line":918},[5947],{"type":42,"tag":322,"props":5948,"children":5949},{},[5950],{"type":48,"value":5951},"- `UNRATE` - Unemployment rate (monthly, %)\n",{"type":42,"tag":322,"props":5953,"children":5954},{"class":324,"line":927},[5955],{"type":42,"tag":322,"props":5956,"children":5957},{},[5958],{"type":48,"value":5959},"- `T10Y2Y` - 10Y minus 2Y Treasury yield spread (daily, %). Negative = inversion.\n",{"type":42,"tag":322,"props":5961,"children":5962},{"class":324,"line":935},[5963],{"type":42,"tag":322,"props":5964,"children":5965},{},[5966],{"type":48,"value":5967},"- `GDPC1` - Real GDP (quarterly, billions of chained 2017 dollars)\n",{"type":42,"tag":322,"props":5969,"children":5970},{"class":324,"line":944},[5971],{"type":42,"tag":322,"props":5972,"children":5973},{"emptyLinePlaceholder":537},[5974],{"type":48,"value":540},{"type":42,"tag":322,"props":5976,"children":5977},{"class":324,"line":953},[5978],{"type":42,"tag":322,"props":5979,"children":5980},{},[5981],{"type":48,"value":5982},"## Data caveats\n",{"type":42,"tag":322,"props":5984,"children":5985},{"class":324,"line":962},[5986],{"type":42,"tag":322,"props":5987,"children":5988},{},[5989],{"type":48,"value":5990},"- All dates are UTC. FMP dates are fiscal quarter end (may not match calendar quarter)\n",{"type":42,"tag":322,"props":5992,"children":5994},{"class":324,"line":5993},52,[5995],{"type":42,"tag":322,"props":5996,"children":5997},{},[5998],{"type":48,"value":5999},"- `raw.fmp_fundamentals.date` is the fiscal period end, not filing date - there's typically a 30–60 day lag between period end and when the numbers are reported\n",{"type":42,"tag":322,"props":6001,"children":6003},{"class":324,"line":6002},53,[6004],{"type":42,"tag":322,"props":6005,"children":6006},{},[6007],{"type":48,"value":6008},"- `raw.yahoo_prices.close` is adjusted for splits and dividends; `raw.yahoo_prices.open` is not\n",{"type":42,"tag":322,"props":6010,"children":6012},{"class":324,"line":6011},54,[6013],{"type":42,"tag":322,"props":6014,"children":6015},{},[6016],{"type":48,"value":6017},"- `raw.fred_macro` series have different frequencies (daily / monthly / quarterly). When joining to prices, align on the price date and use the most recent macro value (`last_value ignore nulls over ...` or a backward-looking window)\n",{"type":42,"tag":322,"props":6019,"children":6021},{"class":324,"line":6020},55,[6022],{"type":42,"tag":322,"props":6023,"children":6024},{"emptyLinePlaceholder":537},[6025],{"type":48,"value":540},{"type":42,"tag":322,"props":6027,"children":6029},{"class":324,"line":6028},56,[6030],{"type":42,"tag":322,"props":6031,"children":6032},{},[6033],{"type":48,"value":6034},"## Query guidelines\n",{"type":42,"tag":322,"props":6036,"children":6038},{"class":324,"line":6037},57,[6039],{"type":42,"tag":322,"props":6040,"children":6041},{},[6042],{"type":48,"value":6043},"- For all analytical questions, start with `reports.ticker_quarterly`. Most questions are a SELECT against this table with a WHERE on `regime_at_qend` or a comparison across symbols.\n",{"type":42,"tag":322,"props":6045,"children":6047},{"class":324,"line":6046},58,[6048],{"type":42,"tag":322,"props":6049,"children":6050},{},[6051],{"type":48,"value":6052},"- When comparing fundamentals across time, prefer the pre-computed `ttm_*` columns over recomputing TTM from `staging.fundamentals`\n",{"type":42,"tag":322,"props":6054,"children":6056},{"class":324,"line":6055},59,[6057],{"type":42,"tag":322,"props":6058,"children":6059},{},[6060],{"type":48,"value":6061},"- If you need price detail beyond `quarterly_return` and `price_at_quarter_end`, drop to `staging.prices` and join on (symbol, date) - but always filter by date range first; the table has years of daily data per ticker\n",{"type":42,"tag":322,"props":6063,"children":6065},{"class":324,"line":6064},60,[6066],{"type":42,"tag":322,"props":6067,"children":6068},{},[6069],{"type":48,"value":6070},"- To get latest fundamentals per ticker from staging: `QUALIFY ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY fiscal_quarter_end DESC) = 1`\n",{"type":42,"tag":322,"props":6072,"children":6074},{"class":324,"line":6073},61,[6075],{"type":42,"tag":322,"props":6076,"children":6077},{},[6078],{"type":48,"value":6079},"- Never join `staging.fundamentals` directly to `staging.prices` on date - their grains differ. Use `reports.ticker_quarterly` (already aligned) or align fundamentals to the next available price date.\n",{"type":42,"tag":51,"props":6081,"children":6082},{},[6083,6085,6090,6092,6097],{"type":48,"value":6084},"When the agent is done, your workspace has two ",{"type":42,"tag":57,"props":6086,"children":6088},{"className":6087},[],[6089],{"type":48,"value":69},{"type":48,"value":6091}," files working in tandem: the root one with Bruin rules (applies everywhere), and ",{"type":42,"tag":57,"props":6093,"children":6095},{"className":6094},[],[6096],{"type":48,"value":5216},{"type":48,"value":6098}," with finance domain context (applies when the agent is working inside this pipeline). Restart your AI coding tool (new Claude Code session / reopen Cursor) so it picks up the new file.",{"type":42,"tag":43,"props":6100,"children":6102},{"id":6101},"_3-sanity-check-the-context",[6103],{"type":48,"value":6104},"3. Sanity-check the context",{"type":42,"tag":51,"props":6106,"children":6107},{},[6108,6110,6115],{"type":48,"value":6109},"Ask your agent a scoping question that should only be answerable if it read ",{"type":42,"tag":57,"props":6111,"children":6113},{"className":6112},[],[6114],{"type":48,"value":69},{"type":48,"value":3346},{"type":42,"tag":157,"props":6117,"children":6118},{},[6119],{"type":42,"tag":51,"props":6120,"children":6121},{},[6122],{"type":48,"value":6123},"Which FRED series in this project captures yield-curve inversion, and what value indicates one?",{"type":42,"tag":51,"props":6125,"children":6126},{},[6127,6129,6134,6136,6141,6143,6148],{"type":48,"value":6128},"The agent should answer with ",{"type":42,"tag":57,"props":6130,"children":6132},{"className":6131},[],[6133],{"type":48,"value":3690},{"type":48,"value":6135}," and \"negative values\". If it fumbles or asks you instead, the pipeline-level ",{"type":42,"tag":57,"props":6137,"children":6139},{"className":6138},[],[6140],{"type":48,"value":69},{"type":48,"value":6142}," wasn't loaded - restart the session, and make sure the agent is working inside the ",{"type":42,"tag":57,"props":6144,"children":6146},{"className":6145},[],[6147],{"type":48,"value":993},{"type":48,"value":6149}," folder.",{"type":42,"tag":43,"props":6151,"children":6152},{"id":998},[6153],{"type":48,"value":1001},{"type":42,"tag":51,"props":6155,"children":6156},{},[6157,6159,6164,6166,6171],{"type":48,"value":6158},"Your agent now has three layers of context: workspace-level Bruin rules (root ",{"type":42,"tag":57,"props":6160,"children":6162},{"className":6161},[],[6163],{"type":48,"value":69},{"type":48,"value":6165},"), per-column schema descriptions (auto-generated into the asset YAML), and pipeline-specific domain knowledge (",{"type":42,"tag":57,"props":6167,"children":6169},{"className":6168},[],[6170],{"type":48,"value":5216},{"type":48,"value":6172},"). Every question you ask from here on out is reasoned against this stack rather than guessed from column names. You've just done what takes a new human analyst a month of onboarding.",{"type":42,"tag":1015,"props":6174,"children":6175},{},[6176],{"type":48,"value":1019},{"title":7,"searchDepth":18,"depth":18,"links":6178},[6179,6180,6181,6182,6183,6184],{"id":45,"depth":18,"text":49},{"id":74,"depth":18,"text":77},{"id":5233,"depth":18,"text":5236},{"id":5511,"depth":18,"text":5514},{"id":6101,"depth":18,"text":6104},{"id":998,"depth":18,"text":1001},"content:tutorials:stock-analyst-101:enhance-context.md","tutorials/stock-analyst-101/enhance-context.md","tutorials/stock-analyst-101/enhance-context",{"_path":6189,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":6190,"description":6191,"date":10,"readingTime":583,"category":12,"tags":6192,"difficulty":17,"module":5,"step":403,"journeys":6193,"roles":6194,"learnMore":6195,"author":6200,"body":6201,"_type":519,"_id":6849,"_source":1032,"_file":6850,"_stem":6851,"_extension":1035},"/tutorials/stock-analyst-101/ask-the-question","Ask the Real Analyst Question","Put the stack to work. Combine FMP fundamentals, Yahoo prices, and FRED macro to answer the kind of question analysts actually get paid for.",[14,15,1831,16,22],[20],[22,23],[6196,6199],{"label":6197,"url":6198},"Bruin query command","https://getbruin.com/docs/bruin/commands/query.html",{"label":5089,"url":5090},{"name":35,"role":36,"image":37},{"type":39,"children":6202,"toc":6839},[6203,6207,6212,6216,6228,6247,6253,6258,6409,6415,6420,6493,6519,6525,6530,6559,6582,6603,6625,6630,6636,6641,6687,6700,6706,6778,6782,6787,6795],{"type":42,"tag":43,"props":6204,"children":6205},{"id":45},[6206],{"type":48,"value":49},{"type":42,"tag":51,"props":6208,"children":6209},{},[6210],{"type":48,"value":6211},"Ask your AI analyst the signature question this module was built for - one that requires all three data sources at once. Then learn the habits that get you consistently good answers.",{"type":42,"tag":43,"props":6213,"children":6214},{"id":74},[6215],{"type":48,"value":77},{"type":42,"tag":51,"props":6217,"children":6218},{},[6219,6221,6226],{"type":48,"value":6220},"The whole point of the last five steps - the CLI, the MCP, the ingestion, the staging + reports layers, the context file - was to make ",{"type":42,"tag":94,"props":6222,"children":6223},{},[6224],{"type":48,"value":6225},"this step",{"type":48,"value":6227}," possible: asking a question that used to take a junior analyst a week, and getting a worked answer in 30 seconds.",{"type":42,"tag":51,"props":6229,"children":6230},{},[6231,6233,6238,6240,6245],{"type":48,"value":6232},"You built ",{"type":42,"tag":57,"props":6234,"children":6236},{"className":6235},[],[6237],{"type":48,"value":4671},{"type":48,"value":6239}," in Step 4 specifically so questions like this one don't require re-deriving TTM FCF margin or aligning fundamentals-to-prices every session. Your AGENTS.md tells the agent to default to ",{"type":42,"tag":57,"props":6241,"children":6243},{"className":6242},[],[6244],{"type":48,"value":4196},{"type":48,"value":6246}," - so this question is mostly a SELECT against a pre-joined table.",{"type":42,"tag":43,"props":6248,"children":6250},{"id":6249},"the-signature-question",[6251],{"type":48,"value":6252},"The signature question",{"type":42,"tag":51,"props":6254,"children":6255},{},[6256],{"type":48,"value":6257},"Paste this into your AI tool:",{"type":42,"tag":157,"props":6259,"children":6260},{},[6261,6279,6328,6346,6359,6378,6404],{"type":42,"tag":51,"props":6262,"children":6263},{},[6264,6265,6270,6272,6277],{"type":48,"value":4001},{"type":42,"tag":57,"props":6266,"children":6268},{"className":6267},[],[6269],{"type":48,"value":4671},{"type":48,"value":6271},", find tickers (from the 5 I ingested) that meet all of the following over the ",{"type":42,"tag":94,"props":6273,"children":6274},{},[6275],{"type":48,"value":6276},"last 4 quarters available",{"type":48,"value":6278}," in the table:",{"type":42,"tag":203,"props":6280,"children":6281},{},[6282,6312],{"type":42,"tag":88,"props":6283,"children":6284},{},[6285,6290,6292,6297,6299,6304,6306,6311],{"type":42,"tag":57,"props":6286,"children":6288},{"className":6287},[],[6289],{"type":48,"value":4730},{"type":48,"value":6291}," has ",{"type":42,"tag":94,"props":6293,"children":6294},{},[6295],{"type":48,"value":6296},"improved",{"type":48,"value":6298}," quarter over quarter (positive ",{"type":42,"tag":57,"props":6300,"children":6302},{"className":6301},[],[6303],{"type":48,"value":4752},{"type":48,"value":6305}," in each of the last 4 quarters, or strictly increasing ",{"type":42,"tag":57,"props":6307,"children":6309},{"className":6308},[],[6310],{"type":48,"value":4730},{"type":48,"value":2164},{"type":42,"tag":88,"props":6313,"children":6314},{},[6315,6320,6321,6326],{"type":42,"tag":57,"props":6316,"children":6318},{"className":6317},[],[6319],{"type":48,"value":4793},{"type":48,"value":6291},{"type":42,"tag":94,"props":6322,"children":6323},{},[6324],{"type":48,"value":6325},"underperformed",{"type":48,"value":6327}," the equal-weighted average across the 5 tickers by more than 10 percentage points cumulatively over the same period",{"type":42,"tag":51,"props":6329,"children":6330},{},[6331,6333,6338,6340,6345],{"type":48,"value":6332},"Then split the qualifying set by ",{"type":42,"tag":94,"props":6334,"children":6335},{},[6336],{"type":48,"value":6337},"macro regime",{"type":48,"value":6339}," using ",{"type":42,"tag":57,"props":6341,"children":6343},{"className":6342},[],[6344],{"type":48,"value":4832},{"type":48,"value":3346},{"type":42,"tag":84,"props":6347,"children":6348},{},[6349,6354],{"type":42,"tag":88,"props":6350,"children":6351},{},[6352],{"type":48,"value":6353},"'inverted' - yield curve was inverted at the quarter end",{"type":42,"tag":88,"props":6355,"children":6356},{},[6357],{"type":48,"value":6358},"'normal' - yield curve was positive at the quarter end",{"type":42,"tag":51,"props":6360,"children":6361},{},[6362,6364,6369,6371,6376],{"type":48,"value":6363},"For each ticker that qualifies, show: ticker, the 4 quarterly ",{"type":42,"tag":57,"props":6365,"children":6367},{"className":6366},[],[6368],{"type":48,"value":4730},{"type":48,"value":6370}," values, cumulative ",{"type":42,"tag":57,"props":6372,"children":6374},{"className":6373},[],[6375],{"type":48,"value":4793},{"type":48,"value":6377}," vs. the peer average, and which regime dominated the window.",{"type":42,"tag":51,"props":6379,"children":6380},{},[6381,6383,6388,6390,6395,6397,6402],{"type":48,"value":6382},"Default to ",{"type":42,"tag":57,"props":6384,"children":6386},{"className":6385},[],[6387],{"type":48,"value":4671},{"type":48,"value":6389},". Only drop to ",{"type":42,"tag":57,"props":6391,"children":6393},{"className":6392},[],[6394],{"type":48,"value":4180},{"type":48,"value":6396}," or ",{"type":42,"tag":57,"props":6398,"children":6400},{"className":6399},[],[6401],{"type":48,"value":3973},{"type":48,"value":6403}," if you need to validate a number that looks off, and tell me when you do.",{"type":42,"tag":51,"props":6405,"children":6406},{},[6407],{"type":48,"value":6408},"Show me the SQL first. Only execute once I approve the plan.",{"type":42,"tag":43,"props":6410,"children":6412},{"id":6411},"what-to-look-for-in-the-agents-plan",[6413],{"type":48,"value":6414},"What to look for in the agent's plan",{"type":42,"tag":51,"props":6416,"children":6417},{},[6418],{"type":48,"value":6419},"Before approving the SQL, check that the agent:",{"type":42,"tag":84,"props":6421,"children":6422},{},[6423,6446,6458,6470,6475],{"type":42,"tag":88,"props":6424,"children":6425},{},[6426,6428,6433,6435,6440,6441],{"type":48,"value":6427},"Queries ",{"type":42,"tag":57,"props":6429,"children":6431},{"className":6430},[],[6432],{"type":48,"value":4671},{"type":48,"value":6434}," as the primary source - not ",{"type":42,"tag":57,"props":6436,"children":6438},{"className":6437},[],[6439],{"type":48,"value":3973},{"type":48,"value":6396},{"type":42,"tag":57,"props":6442,"children":6444},{"className":6443},[],[6445],{"type":48,"value":4180},{"type":42,"tag":88,"props":6447,"children":6448},{},[6449,6451,6456],{"type":48,"value":6450},"Uses the pre-computed ",{"type":42,"tag":57,"props":6452,"children":6454},{"className":6453},[],[6455],{"type":48,"value":4730},{"type":48,"value":6457}," column instead of recomputing FCF / revenue from raw",{"type":42,"tag":88,"props":6459,"children":6460},{},[6461,6463,6468],{"type":48,"value":6462},"Uses ",{"type":42,"tag":57,"props":6464,"children":6466},{"className":6465},[],[6467],{"type":48,"value":4832},{"type":48,"value":6469}," for the macro regime split (already calculated in staging)",{"type":42,"tag":88,"props":6471,"children":6472},{},[6473],{"type":48,"value":6474},"Computes the peer average across the 5 tickers within the same query (window function or subquery)",{"type":42,"tag":88,"props":6476,"children":6477},{},[6478,6480,6485,6486,6491],{"type":48,"value":6479},"States explicitly if it does need to drop into ",{"type":42,"tag":57,"props":6481,"children":6483},{"className":6482},[],[6484],{"type":48,"value":4180},{"type":48,"value":6396},{"type":42,"tag":57,"props":6487,"children":6489},{"className":6488},[],[6490],{"type":48,"value":3973},{"type":48,"value":6492}," - and why",{"type":42,"tag":51,"props":6494,"children":6495},{},[6496,6498,6503,6505,6517],{"type":48,"value":6497},"If the agent reaches into ",{"type":42,"tag":57,"props":6499,"children":6501},{"className":6500},[],[6502],{"type":48,"value":4023},{"type":48,"value":6504}," to recompute things, push back: ",{"type":42,"tag":450,"props":6506,"children":6507},{},[6508,6510,6515],{"type":48,"value":6509},"\"",{"type":42,"tag":57,"props":6511,"children":6513},{"className":6512},[],[6514],{"type":48,"value":4671},{"type":48,"value":6516}," already has TTM FCF margin and the regime - use that.\"",{"type":48,"value":6518}," This is the discipline that makes the layered pipeline pay off.",{"type":42,"tag":43,"props":6520,"children":6522},{"id":6521},"follow-up-questions-to-try",[6523],{"type":48,"value":6524},"Follow-up questions to try",{"type":42,"tag":51,"props":6526,"children":6527},{},[6528],{"type":48,"value":6529},"Once the first question runs clean, keep pulling threads - tap any prompt below to copy it:",{"type":42,"tag":157,"props":6531,"children":6532},{},[6533],{"type":42,"tag":51,"props":6534,"children":6535},{},[6536,6538,6543,6545,6550,6552,6557],{"type":48,"value":6537},"For the qualifying tickers, pull operating margin and R&D spend from ",{"type":42,"tag":57,"props":6539,"children":6541},{"className":6540},[],[6542],{"type":48,"value":4326},{"type":48,"value":6544}," for the same quarters. Does the trend change your interpretation? (Acceptable to drop to ",{"type":42,"tag":57,"props":6546,"children":6548},{"className":6547},[],[6549],{"type":48,"value":4180},{"type":48,"value":6551}," here - these columns aren't surfaced in ",{"type":42,"tag":57,"props":6553,"children":6555},{"className":6554},[],[6556],{"type":48,"value":4671},{"type":48,"value":6558},".)",{"type":42,"tag":157,"props":6560,"children":6561},{},[6562],{"type":42,"tag":51,"props":6563,"children":6564},{},[6565,6567,6572,6574,6580],{"type":48,"value":6566},"Rerun the analysis using ",{"type":42,"tag":57,"props":6568,"children":6570},{"className":6569},[],[6571],{"type":48,"value":4671},{"type":48,"value":6573}," but tighten the threshold: require ",{"type":42,"tag":57,"props":6575,"children":6577},{"className":6576},[],[6578],{"type":48,"value":6579},"fcf_margin_qoq_change > 0.02",{"type":48,"value":6581}," (200bps) in each of the last 4 quarters. Does the set of qualifiers narrow?",{"type":42,"tag":157,"props":6583,"children":6584},{},[6585],{"type":42,"tag":51,"props":6586,"children":6587},{},[6588,6589,6594,6596,6601],{"type":48,"value":4001},{"type":42,"tag":57,"props":6590,"children":6592},{"className":6591},[],[6593],{"type":48,"value":4671},{"type":48,"value":6595},", overlay ",{"type":42,"tag":57,"props":6597,"children":6599},{"className":6598},[],[6600],{"type":48,"value":4818},{"type":48,"value":6602}," for the qualifying tickers. Were they concentrated in periods with rising rates?",{"type":42,"tag":157,"props":6604,"children":6605},{},[6606],{"type":42,"tag":51,"props":6607,"children":6608},{},[6609,6611,6616,6618,6623],{"type":48,"value":6610},"For the qualifying tickers, query ",{"type":42,"tag":57,"props":6612,"children":6614},{"className":6613},[],[6615],{"type":48,"value":4484},{"type":48,"value":6617}," to see what unemployment (",{"type":42,"tag":57,"props":6619,"children":6621},{"className":6620},[],[6622],{"type":48,"value":4523},{"type":48,"value":6624},") was doing during their underperformance windows. Any relationship worth investigating?",{"type":42,"tag":51,"props":6626,"children":6627},{},[6628],{"type":48,"value":6629},"Each of these takes a real analyst 30–60 minutes to produce manually. Your agent does them in the time it takes to write the prompt.",{"type":42,"tag":43,"props":6631,"children":6633},{"id":6632},"save-the-good-queries",[6634],{"type":48,"value":6635},"Save the good queries",{"type":42,"tag":51,"props":6637,"children":6638},{},[6639],{"type":48,"value":6640},"When the agent writes a SQL query you like, ask it to save it as a Bruin SQL asset in the reports layer:",{"type":42,"tag":157,"props":6642,"children":6643},{},[6644],{"type":42,"tag":51,"props":6645,"children":6646},{},[6647,6649,6655,6657,6663,6665,6671,6673,6678,6680,6685],{"type":48,"value":6648},"Take that query and save it as ",{"type":42,"tag":57,"props":6650,"children":6652},{"className":6651},[],[6653],{"type":48,"value":6654},"stock-analyst-101/assets/reports/fcf_vs_price_underperformers.sql",{"type":48,"value":6656}," materialized as ",{"type":42,"tag":57,"props":6658,"children":6660},{"className":6659},[],[6661],{"type":48,"value":6662},"reports.fcf_vs_price_underperformers",{"type":48,"value":6664},". Use materialization ",{"type":42,"tag":57,"props":6666,"children":6668},{"className":6667},[],[6669],{"type":48,"value":6670},"view",{"type":48,"value":6672}," (cheap, always re-derives from ",{"type":42,"tag":57,"props":6674,"children":6676},{"className":6675},[],[6677],{"type":48,"value":4671},{"type":48,"value":6679},"). Add a top-level description, column descriptions, and a ",{"type":42,"tag":57,"props":6681,"children":6683},{"className":6682},[],[6684],{"type":48,"value":4843},{"type":48,"value":6686}," tag.",{"type":42,"tag":51,"props":6688,"children":6689},{},[6690,6692,6698],{"type":48,"value":6691},"Now it's part of your pipeline. Next run of ",{"type":42,"tag":57,"props":6693,"children":6695},{"className":6694},[],[6696],{"type":48,"value":6697},"bruin run",{"type":48,"value":6699},", the view is rebuilt from fresh data. You're not just asking questions - you're growing your reports layer with every analysis you save.",{"type":42,"tag":43,"props":6701,"children":6703},{"id":6702},"habits-for-getting-consistently-good-answers",[6704],{"type":48,"value":6705},"Habits for getting consistently good answers",{"type":42,"tag":84,"props":6707,"children":6708},{},[6709,6719,6729,6745,6755],{"type":42,"tag":88,"props":6710,"children":6711},{},[6712,6717],{"type":42,"tag":94,"props":6713,"children":6714},{},[6715],{"type":48,"value":6716},"Ask for the plan before the result.",{"type":48,"value":6718}," Prompts that include \"show me the SQL first and explain the logic\" catch mistakes cheap.",{"type":42,"tag":88,"props":6720,"children":6721},{},[6722,6727],{"type":42,"tag":94,"props":6723,"children":6724},{},[6725],{"type":48,"value":6726},"Be specific about time windows.",{"type":48,"value":6728}," \"Recent\" is ambiguous; \"last 4 fiscal quarters as of today\" is not.",{"type":42,"tag":88,"props":6730,"children":6731},{},[6732,6737,6739,6743],{"type":42,"tag":94,"props":6733,"children":6734},{},[6735],{"type":48,"value":6736},"Name the comparison.",{"type":48,"value":6738}," \"Underperformed\" vs. ",{"type":42,"tag":450,"props":6740,"children":6741},{},[6742],{"type":48,"value":5538},{"type":48,"value":6744}," benchmark? State it. Otherwise the agent picks one and you don't know which.",{"type":42,"tag":88,"props":6746,"children":6747},{},[6748,6753],{"type":42,"tag":94,"props":6749,"children":6750},{},[6751],{"type":48,"value":6752},"When in doubt, ask for counts first.",{"type":48,"value":6754}," \"How many rows satisfy X?\" before \"here are all the rows satisfying X\" - saves you from chasing ghost results.",{"type":42,"tag":88,"props":6756,"children":6757},{},[6758,6769,6771,6776],{"type":42,"tag":94,"props":6759,"children":6760},{},[6761,6763,6768],{"type":48,"value":6762},"Iterate on ",{"type":42,"tag":57,"props":6764,"children":6766},{"className":6765},[],[6767],{"type":48,"value":69},{"type":48,"value":3607},{"type":48,"value":6770}," Every time the agent gets something wrong for a domain reason, add a line to ",{"type":42,"tag":57,"props":6772,"children":6774},{"className":6773},[],[6775],{"type":48,"value":69},{"type":48,"value":6777}," so it doesn't repeat the mistake.",{"type":42,"tag":43,"props":6779,"children":6780},{"id":998},[6781],{"type":48,"value":1001},{"type":42,"tag":51,"props":6783,"children":6784},{},[6785],{"type":48,"value":6786},"You built a complete stock-analyst workstation - ingest, database, context, agent - on a single laptop, in one sitting, without writing SQL or Python yourself. The stack is yours to keep. Swap in different tickers, add new FRED series, plug in a second fundamentals source. Every addition follows the same pattern: prompt the agent, it runs Bruin, the data lands.",{"type":42,"tag":51,"props":6788,"children":6789},{},[6790],{"type":42,"tag":94,"props":6791,"children":6792},{},[6793],{"type":48,"value":6794},"Where to go next",{"type":42,"tag":84,"props":6796,"children":6797},{},[6798,6812,6825],{"type":42,"tag":88,"props":6799,"children":6800},{},[6801,6810],{"type":42,"tag":94,"props":6802,"children":6803},{},[6804],{"type":42,"tag":1913,"props":6805,"children":6807},{"href":6806},"/learn/ai-data-analyst",[6808],{"type":48,"value":6809},"Build an AI Data Analyst",{"type":48,"value":6811}," - the full deep dive on the same MCP + AGENTS.md pattern, covering BigQuery/Redshift/Postgres as destinations",{"type":42,"tag":88,"props":6813,"children":6814},{},[6815,6823],{"type":42,"tag":94,"props":6816,"children":6817},{},[6818],{"type":42,"tag":1913,"props":6819,"children":6820},{"href":30},[6821],{"type":48,"value":6822},"Using Bruin Templates",{"type":48,"value":6824}," - skip scaffolding entirely with pre-built pipelines",{"type":42,"tag":88,"props":6826,"children":6827},{},[6828,6837],{"type":42,"tag":94,"props":6829,"children":6830},{},[6831],{"type":42,"tag":1913,"props":6832,"children":6834},{"href":6833},"/learn/local-ai-analyst-stock-market",[6835],{"type":48,"value":6836},"Local AI Analyst for the Stock Market (video)",{"type":48,"value":6838}," - the BigQuery + full S&P 500 version of this module",{"title":7,"searchDepth":18,"depth":18,"links":6840},[6841,6842,6843,6844,6845,6846,6847,6848],{"id":45,"depth":18,"text":49},{"id":74,"depth":18,"text":77},{"id":6249,"depth":18,"text":6252},{"id":6411,"depth":18,"text":6414},{"id":6521,"depth":18,"text":6524},{"id":6632,"depth":18,"text":6635},{"id":6702,"depth":18,"text":6705},{"id":998,"depth":18,"text":1001},"content:tutorials:stock-analyst-101:ask-the-question.md","tutorials/stock-analyst-101/ask-the-question.md","tutorials/stock-analyst-101/ask-the-question",1777389165436]