File size: 25,032 Bytes
9fe4fad 3020135 9fe4fad 15345ca 9fe4fad fc5b9d0 0225cde 9fe4fad fc5b9d0 ed3fb78 4819a70 fc5b9d0 ed3fb78 3020135 ed3fb78 9fe4fad 3020135 9fe4fad 3020135 c71d3e4 7ac9e43 c71d3e4 9fe4fad 11a500d 9fe4fad 3020135 c71d3e4 9fe4fad 15345ca 9fe4fad c71d3e4 3020135 c71d3e4 3020135 c71d3e4 11a500d c71d3e4 11a500d c71d3e4 9fe4fad | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | ---
title: Agent Usage
summary: How to use TerraFin's agent-facing surfaces from Python, CLI, HTTP, and the hosted assistant widget.
read_when:
- Using TerraFin as an agent tool
- Choosing between stateless and hosted agent surfaces
- Interpreting processing metadata
- Finding the right transport for a workflow
---
# Agent Usage
TerraFin is most useful to agents when it stays on the same path as the product.
That means:
- market and macro responses use the same progressive-history rules as the chart stack
- indicator math matches the chart indicators
- chart-opening uses the same session semantics as the browser UI
- every research response includes `processing`
If you are maintaining the runtime itself, read [hosted-runtime.md](./hosted-runtime.md)
and [architecture.md](./architecture.md). This document is the usage guide.
## If you want to do X, use this tool
Scan this table **first** before reaching for `requests` / `urllib` /
`yfinance` / pandas-html / regex parsers. Every row below is already shipped
with rate-limit, retry, cache, and progressive-history handling.
| If you want to... | Use this tool |
| ---------------------------------------------------------- | ------------------------------------------------------------------- |
| Resolve a ticker/name into a TerraFin route | `resolve(query)` |
| Get a chart-ready OHLC series | `market_data(name, depth, view)` |
| Get a one-asset snapshot (price action + indicators) | `market_snapshot(name, depth, view, force_refresh=False)` β response `asof` is the ISO date of the last bar served; pass `force_refresh=True` only for time-sensitive snapshots (mid-session, freshly-closed bar) to bypass the 24h `yfinance.full` cache |
| Get company profile / valuation fields | `company_info(ticker)` |
| Get earnings history (estimate / reported / surprise) | `earnings(ticker)` |
| Get income / balance / cashflow statement | `financials(ticker, statement, period)` |
| List a ticker's recent 10-K / 10-Q / 8-K filings | `sec_filings(ticker)` |
| Get a single filing's TOC (no full body) | `sec_filing_document(ticker, accession, primaryDocument, form)` |
| Pull one filing section's markdown body | `sec_filing_section(..., sectionSlug, form)` |
| Run DCF / reverse DCF / Graham / relative valuation | `valuation(ticker, ...)` (see SKILL.md for turnaround inputs) |
| Inspect FCF base candidates (3yr_avg / annual / TTM) | `fcf_history(ticker, years)` |
| Get S&P 500 index-level DCF | `sp500_dcf()` |
| Get 5y monthly beta vs mapped benchmark | `beta_estimate(ticker)` |
| Get statistical risk profile (tail risk, drawdown, regime) | `risk_profile(name)` |
| Run a fundamental quality / moat screen | `fundamental_screen(ticker)` |
| Get guru portfolio holdings (Buffett / Marks / Druck.) | `portfolio(guru)` |
| Get FRED-backed economic indicator series | `economic(indicators)` |
| Get macro summary + chart-ready series | `macro_focus(name, depth, view)` |
| Scan calendar events for a month | `calendar_events(year, month, categories, limit)` |
| Detect bubble (super-exp growth + log-periodic osc.) | `lppl_analysis(name, depth, view)` |
| Find chart-shape-similar historical episodes | `similarity_search(ticker, universe, period, top_n)` |
| Get market temperature signals | `fear_greed()`, `market_regime()`, `market_breadth()`, `trailing_forward_pe()` |
| Get top companies by market cap | `top_companies()` |
| Read the user's watchlist | `watchlist()` |
| Get chart-matching technical indicators | `indicators(name, indicators, depth, view)` |
| Get named pattern signals matching the latest bar | `patterns(name, depth, view)` |
| Read which panel/form the user is currently looking at | `current_view_context()` (hosted runtime only) |
| Open a chart artifact bound to the session | `open_chart(name)` (hosted runtime only) |
| List / authenticate / switch hosted models | `terrafin-agent models ...` (see [models.md](./models.md)) |
| Discover capability schemas programmatically | `GET /openapi.json` β filter `paths` to `/agent/api/*` |
Capability signatures with full parameter ranges and worked examples live in
[`skills/terrafin/SKILL.md`](https://github.com/KiUngSong/TerraFin/blob/main/skills/terrafin/SKILL.md).
The route summary further down this page is auto-generated and lists every
HTTP route.
## Don't roll your own
Reach for the TerraFin helper before hand-rolling any of the patterns below.
Each one has been a real source of breakage (rate-limit, cache miss,
parser inconsistency, hidden-API drift).
### SEC EDGAR β don't roll your own scrape
If you find yourself reaching for `urllib.request.urlopen("https://www.sec.gov/...")`,
regex-parsing the accession folder index, or stripping `<html>` tags by hand β
stop. The same content is one tool call away through the parsed + cached path:
| Manual approach (DON'T) | TerraFin tool (DO) |
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `urlopen("https://www.sec.gov/Archives/edgar/data/<cik>/<acc>/")` to list exhibits | `sec_filing_document(ticker, accession, primaryDocument, form="8-K")` β `toc` carries `exhibit-991-press-release` / `exhibit-992-supplemental-material` slugs |
| `urlopen("https://www.sec.gov/.../q1fy27pr.htm")` to grab the earnings PR | `sec_filing_section(..., sectionSlug="exhibit-991-press-release", form="8-K")` β returns parsed markdown body |
| Strip `<p>` / `<table>` / ` ` with regex | already done β `sec_filing_section` returns clean markdown |
| Strip the `/ix?doc=` viewer wrapper off `documentUrl` | use `sec_filing_document` / `sec_filing_section` instead of dereferencing the URL yourself |
Why this matters:
- SEC rate-limits aggressively (~10 req/s per IP). The TerraFin helpers
share a single `SECClient` with rate-limit + retry; raw `urllib` does not.
- Parsed markdown is cached 30 days under `sec.parsed`; raw fetches re-pull
every newsletter run.
- Bypassing the cache risks SEC IP-banning the host.
The `form` arg is required for 8-K exhibit content β service defaults to
`"10-Q"`, and 8-Ks called without `form="8-K"` produce only the 4 KB cover
sheet stub (no exhibits appended). Pull `form` from
`sec_filings(...)["latestByForm"][...]["form"]` (or from any flat-list entry)
and pass it through every call.
### 8-K exhibits β don't bypass `fetch_and_parse_filing`
If you're tempted to call `download_filing(...)` then `parse_sec_filing(...)`
yourself for an 8-K, you'll get the 4 KB cover sheet with **no exhibits
appended**. The exhibit-appending logic lives only in
`fetch_and_parse_filing(cik, accession, doc, "8-K", include_images)`.
| Manual approach (DON'T) | TerraFin tool (DO) |
| -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `parse_sec_filing(download_filing(cik, acc, doc), "8-K")` | `fetch_and_parse_filing(cik, acc, doc, "8-K", include_images=False)` β appends every `EX-99.x` exhibit |
| Manually loop `list_filing_files()` β `download_exhibit()` β `parse_sec_filing()` | `fetch_and_parse_filing(...)` β already does this with per-exhibit error markers |
| Call `sec_filing_section` without `form="8-K"` | always pass `form="8-K"` β service defaults to `"10-Q"` |
The agent-facing path (`sec_filing_section`) wraps `fetch_and_parse_filing`
under the cache; only fall through to `fetch_and_parse_filing` directly when
writing non-agent data-layer code (route handlers, batch ingestion).
### Model catalog β don't reach into `_PROVIDER_CATALOG`
The provider catalog is a public function, not a private dict.
| Manual approach (DON'T) | TerraFin tool (DO) |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `from TerraFin.agent.models.management import _PROVIDER_CATALOG` | `from TerraFin.agent.models.management import list_provider_catalog` |
| `_PROVIDER_CATALOG["openai"].featured_model_refs` | `get_provider_catalog("openai").featured_model_refs` |
| Iterate the private dict to discover providers | `for entry in list_provider_catalog(): ...` |
The private `_PROVIDER_CATALOG` mapping may be renamed or reshaped without
notice; `list_provider_catalog()` / `get_provider_catalog(provider_id)` are
the stable surface.
## Choose a surface
There are two agent-facing HTTP families:
- `GET/POST /agent/api/*`
Stateless capability access, best when another agent already owns the model loop
- `GET/POST /agent/api/runtime/*`
Stateful hosted runtime access, best when TerraFin should own the conversation and tool loop
In the browser, the hosted runtime is exposed through the floating **TerraFin Agent**
widget available on main interface pages such as `/terminal`, `/chart`, and `/stock/<ticker>`.
That panel is always the public surface. There is no guru picker in the default
product flow.
If the deployment does not have a usable hosted model configured, the widget
stays in an info-only state:
- it shows the local setup warning
- it does not create a runtime session
- it does not accept chat input until the hosted model credentials are valid
Hosted runtime chat history is local transcript history:
- each session is stored as an append-only JSONL transcript
- history list and previews are derived from the transcript index
- deleting a session archives the transcript and removes it from active history
- raw tool JSON stays in the transcript for replay, but is hidden from user-facing previews
TerraFin Agent may also route some research questions through hidden investor
roles before replying. Today those roles include Warren Buffett, Howard Marks,
and Stanley Druckenmiller.
Important product rules:
- users still talk only to `TerraFin Agent`
- `TerraFin Agent` is the **orchestrator**; hidden persona roles are
reached by its own LLM via `consult_warren_buffett`,
`consult_howard_marks`, and `consult_stanley_druckenmiller` tool
calls (no pre-intercept router β see the architecture diagrams in
[architecture.md](./architecture.md#orchestrator-persona-subagents))
- the hidden guru path is research-only in v1
- hidden guru sessions are not shown in normal session history
- hidden guru roles cannot be created through the normal public runtime API
- hidden guru session ids are not valid public session/task/approval resources
- internal guru handoff uses a structured memo contract before the main assistant synthesizes a reply
## Disclosure
The hosted TerraFin Agent produces **research-oriented analysis, not personalized
investment advice**. A few properties follow from that framing and should be
called out to downstream product surfaces, integrators, and end users:
- the agent cannot place trades, hold funds, or take fiduciary responsibility
- outputs are grounded in tool results and what the user says in the same
session; the agent should not invent numbers it has not seen in a tool result
- persona consults (Buffett, Marks, Druckenmiller) are framed as research
voices, not registered advisor recommendations
- a `confidence` score β₯ 80 returned by a persona consult carries at least one
citation β the `GuruResearchMemo` validator clamps unsupported high-confidence
memos to 60 before returning them to the orchestrator (see
[guru/memo.py](https://github.com/KiUngSong/TerraFin/blob/main/src/TerraFin/agent/guru/memo.py))
The orchestrator's system prompt carries a matching `DISCLOSURE` paragraph so the
model stays inside this framing. Product surfaces that embed the widget or call
the runtime HTTP API are responsible for any **user-facing** disclosure copy
their jurisdiction requires β the agent itself does not render one.
## Choose a transport
| Transport | Use it when... |
|-----------|----------------|
| Python client | TerraFin is importable locally and low latency matters |
| HTTP API | TerraFin is already running as a service |
| CLI | Shell composition is the simplest fit |
| Skill artifact | Another agent environment needs portable instructions |
`TerraFinAgentClient(transport="auto")` follows the normal rule:
1. Python when no `base_url` is set
2. HTTP when a `base_url` is set
## Default request policy
For market and macro requests:
- start with `depth="auto"`
- inspect the returned `processing`
- rerun with `depth="full"` only when the task genuinely needs long-range context
For company info, earnings, financials, portfolio, and calendar data:
- the payload should already be complete
- `processing.isComplete` is expected to be `true`
Charts are optional. Open them when the chart itself materially helps the task.
## Processing metadata
Every structured research response includes a top-level `processing` object.
```json
{
"processing": {
"requestedDepth": "auto",
"resolvedDepth": "recent",
"loadedStart": "2023-04-04",
"loadedEnd": "2026-04-04",
"isComplete": false,
"hasOlder": true,
"sourceVersion": "yfinance-v2",
"view": "weekly"
}
}
```
| Field | Meaning |
|-------|---------|
| `requestedDepth` | What the caller asked for |
| `resolvedDepth` | What TerraFin actually returned |
| `loadedStart` / `loadedEnd` | Loaded time span for time-series tasks |
| `isComplete` | Whether older data still exists outside the response |
| `hasOlder` | Whether the request can be deepened |
| `sourceVersion` | Provider/cache version hint |
| `view` | Effective timeframe transform |
## Common tasks
Multi-step task recipes. For a one-row "what tool do I need" lookup, scan the
[tool-index table at the top](#if-you-want-to-do-x-use-this-tool) instead.
Rows marked **(helper)** are composed module-level functions exported from
`from TerraFin.agent import β¦` β not registered capabilities. They wrap
one or more capabilities (e.g. `compare_assets` calls `resolve` + `market_snapshot`
under the hood). They're not in the 30-row capability table because they
don't appear in the agent capability registry.
| Task | Recommended entrypoint |
|------|------------------------|
| Ticker brief | `resolve(...)` then `market_snapshot(...)` |
| Market snapshot | `market_snapshot(name, depth="auto", view="daily")` |
| Compare assets | `compare_assets([...], depth="auto", view="daily")` **(helper)** |
| Macro context | `macro_context(name, depth="auto", view="daily")` **(helper)** |
| Portfolio context | `portfolio_context(guru)` **(helper)** |
| Stock fundamentals | `stock_fundamentals(ticker, statement="income", period="annual")` **(helper)** |
| Stock DCF | `valuation(ticker, projection_years=..., fcf_base_source=..., breakeven_year=..., breakeven_cash_flow_per_share=..., post_breakeven_growth_pct=...)` |
| FCF history candidates | `fcf_history(ticker, years=10)` |
| SEC filings | `sec_filings(ticker)` β `sec_filing_document(..., form=...)` β `sec_filing_section(..., sectionSlug=..., form=...)`. **Pass the actual `form` string** ("10-K" / "10-Q" / "8-K" / "8-K/A") on every call β service defaults to "10-Q". For 8-K, the TOC includes `exhibit-991-press-release` / `exhibit-992-supplemental-material` slugs holding the earnings PR + CFO commentary bodies. |
| Sentiment / breadth | `fear_greed()`, `market_regime()`, `market_breadth()`, `trailing_forward_pe()` |
| Calendar scan | `calendar_events(year=..., month=..., categories=..., limit=...)` |
| Bubble analysis | `lppl_analysis(name, depth="auto", view="daily")` |
| Chart similarity search | `similarity_search(ticker, universe="sp500+nasdaq100+kospi200", period="1y", top_n=20)` |
| Open chart | `open_chart(...)` when the chart is explicitly useful |
> See [Don't roll your own β SEC EDGAR](#sec-edgar--dont-roll-your-own-scrape)
> for the anti-pattern table and why the helper exists. The summary: pass
> `form="8-K"` explicitly (service defaults to `"10-Q"`), pull it from
> `sec_filings(...)["latestByForm"][...]["form"]`.
> The full per-capability call signature, parameter ranges, and worked
> examples (including DCF turnaround mode) live in
> [`skills/terrafin/SKILL.md`](https://github.com/KiUngSong/TerraFin/blob/main/skills/terrafin/SKILL.md) β
> the skill is the authoritative capability reference for both this doc and
> external agents.
## Minimal examples
### Python client
```python
from TerraFin.agent import TerraFinAgentClient
client = TerraFinAgentClient()
snapshot = client.market_snapshot("AAPL", depth="auto", view="daily")
```
### Hosted runtime helper
```python
from TerraFin.agent import create_runtime_session
session = create_runtime_session("terrafin-assistant")
session.send("Compare the S&P 500 and Nasdaq.")
session.display_notebook()
```
### CLI
```bash
terrafin-agent snapshot AAPL
terrafin-agent runtime-create-session terrafin-assistant
terrafin-agent models list --all
```
### HTTP
```bash
curl "http://127.0.0.1:8001/agent/api/market-snapshot?ticker=AAPL&depth=auto&view=daily"
curl -X POST "http://127.0.0.1:8001/agent/api/runtime/sessions" \
-H "Content-Type: application/json" \
-d '{"agentName":"terrafin-assistant"}'
```
### Browser UI
```text
http://127.0.0.1:8001/terminal
Use the TerraFin Agent button in the lower-right corner.
```
## Route summary
Stateless capability routes (every hosted-runtime tool also has a parity HTTP
route under `/agent/api/*` β see `skills/terrafin/SKILL.md` for the full
30-capability table with Python / CLI signatures).
<!-- The route table below is auto-generated from
src/TerraFin/agent/runtime/capability.py by
`python scripts/generate-agent-artefacts.py`. Edit the registry, not
this section. Hand-edits will be overwritten. -->
<!-- generated:route-summary:begin -->
Data + chart:
- `GET /agent/api/calendar` β TerraFin calendar events for a month.
- `GET /agent/api/company` β Company profile and valuation fields for a ticker.
- `GET /agent/api/earnings` β Earnings history (estimate / reported / surprise) for a ticker.
- `GET /agent/api/economic` β Economic indicator series (FRED-backed).
- `GET /agent/api/financials` β Financial statement table (income / balance / cashflow) for a ticker.
- `GET /agent/api/indicators` β Chart-matching technical indicators for one asset.
- `GET /agent/api/lppl` β LPPL bubble analysis (super-exponential growth + log-periodic oscillation detection).
- `GET /agent/api/macro-focus` β Macro summary plus chart-ready series for one instrument.
- `GET /agent/api/market-data` β Chart-ready OHLC time series for one asset.
- `GET /agent/api/market-snapshot` β Compact market snapshot for one asset.
- `GET /agent/api/portfolio` β Guru portfolio holdings and summary metadata.
- `GET /agent/api/resolve` β Resolve a free-form query into a TerraFin route.
Valuation + fundamentals:
- `GET /agent/api/beta-estimate` β 5-year monthly beta with adjusted beta, RΒ², benchmark.
- `GET /agent/api/fundamental-screen` β Fundamental quality and moat screen for a ticker.
- `GET /agent/api/risk-profile` β Statistical risk profile (tail risk, convexity, vol regime, drawdown).
- `GET /agent/api/sp500-dcf` β Full S&P 500 DCF valuation (scenarios, sensitivity, methods).
- `GET /agent/api/valuation` β DCF (incl. turnaround mode), reverse DCF, relative valuation, Graham number.
SEC filings:
- `GET /agent/api/sec-filing-document` β Filing table-of-contents (sections + char counts) without full body.
- `GET /agent/api/sec-filing-section` β Verbatim markdown body of one filing section by slug.
- `GET /agent/api/sec-filings` β List recent 10-K / 10-Q / 8-K filings for a ticker with EDGAR URLs.
Sentiment / breadth / market state:
- `GET /agent/api/fear-greed` β CNN Fear & Greed index β score, rating, history.
- `GET /agent/api/market-breadth` β Standalone market-breadth metrics (% advancing, new highs, etc.).
- `GET /agent/api/market-regime` β Market regime classification with confidence and signals.
- `GET /agent/api/top-companies` β Top companies by market cap (private API or yfinance fallback).
- `GET /agent/api/trailing-forward-pe` β S&P 500 trailing vs forward P/E spread (history + summary).
- `GET /agent/api/watchlist` β The user's current watchlist (read-only).
Other:
- `GET /agent/api/fcf-history` β FCF history + 3yr-avg / latest-annual / TTM candidates.
- `GET /agent/api/patterns` β Named market patterns matching the latest bar for one asset.
- `GET /agent/api/similarity-search` β Chart-pattern similarity search across a stock universe.
<!-- generated:route-summary:end -->
> **View context is read-only.** The hosted runtime exposes a
> `current_view_context()` tool that returns the panel and form state the
> user is currently looking at β including the DCF input form's
> `projectionYears` / `fcfBaseSource` / `turnaroundMode` selections, the FCF
> history candidates already loaded, and the auto-selected DCF base source.
> The agent **cannot currently write back to the user's frontend form** (no
> `apply_dcf_inputs` / `set_form_state` tool exists). If the agent suggests
> input values, the user applies them manually. This gap is tracked.
Hosted runtime routes:
- `GET /agent/api/runtime/agents`
- `POST /agent/api/runtime/sessions`
- `GET /agent/api/runtime/sessions`
- `GET /agent/api/runtime/sessions/{session_id}`
- `DELETE /agent/api/runtime/sessions/{session_id}`
- `POST /agent/api/runtime/sessions/{session_id}/messages`
- `GET /agent/api/runtime/sessions/{session_id}/approvals`
- `GET /agent/api/runtime/tasks/{task_id}`
- `POST /agent/api/runtime/tasks/{task_id}/cancel`
- `GET /agent/api/runtime/approvals/{approval_id}`
- `POST /agent/api/runtime/approvals/{approval_id}/approve`
- `POST /agent/api/runtime/approvals/{approval_id}/deny`
OpenAPI is available at `/openapi.json`.
## Managing hosted models
The hosted runtime now has a small built-in model manager. Use it when you want
OpenAI, Gemini, or GitHub Copilot without hand-editing env vars every time.
This command family was inspired by OpenClaw's provider/model UX, but TerraFin
implements and persists it through its own runtime and CLI layers. See
[models.md](./models.md) for the explicit attribution and boundary.
```bash
terrafin-agent models list --all
terrafin-agent models current
terrafin-agent models use github-copilot/gpt-4o
terrafin-agent models auth login-github-copilot --set-default
```
`login-github-copilot` now runs a full GitHub device-login flow by default. For
non-interactive shells, pass `--token` instead.
For the full model-management guide, read [models.md](./models.md).
## Read next
- [hosted-runtime.md](./hosted-runtime.md)
- [models.md](./models.md)
- [architecture.md](./architecture.md)
- [../interface.md](../interface.md)
- [TerraFin skill on GitHub](https://github.com/KiUngSong/TerraFin/blob/main/skills/terrafin/SKILL.md)
|