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>` / `&nbsp;` 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)