MSN can serve the previous session's close for hours after IDX closes;
on 2026-10-16 at 16:53 WIB it still returned the 15th. Quotes and
screener rows now carry `behind_session`, true when `as_of` is before
the latest weekday whose session has ended (16:15 WIB). It is computed
on return, not cached. The quote table notes such quotes, and the
get_quotes description explains the field.
Closes#50
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
`idx stocks flow` now reads IPOT by default, which needs nothing installed:
per session, the all-investor broker summary gives the value traded and
the foreign one gives foreign buying (its footer), the foreign net and
selling (buying less the net), across all boards, through the broker
summary cache. IPOT's foreign net matched IDX's estimate within 0.3 B on
BBCA 2026-10-12 to 16.
`--source idx` (and `source` on get_foreign_flow) keeps IDX's trading
summary: exact share counts, close and the non-regular share, behind
curl-impersonate and Cloudflare.
- ForeignFlowDay gains foreign_buy_value, foreign_sell_value and
foreign_share_bps for both sources (estimated at the session average
for IDX); ForeignFlow gains source, the value totals and rounded.
- The table lays out each source's figures; the live smoke runs both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
IPOT's investor filter splits each broker row by client domicile, but its
footer then gives only that side's buying (BBCA 2026-10-16: foreign 1.7 T,
domestic 4.9 T of 6.6 T). The foreign net gives the selling on all boards:
foreign 1.7 + 2.3 = 4.0 T (IDX: about 3.95 T regular), domestic
4.9 - 2.3 = 2.6 T.
- BrokerSummary gains buy_value and sell_value: the total for all
investors, the footer and the derived selling for one side (selling is
null with a board filter, where the net covers other boards).
- Bandar weighs the top N buyers' share of the value bought against the
top N sellers' share of the value sold, so `--investor foreign|domestic`
reads that side alone; for all investors the readings are unchanged.
One side on one board is refused, as there is no selling to weigh.
- Tables print what the side bought and sold; fixtures for foreign and
domestic on all boards were recorded from IPOT.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
IDX's Value is regular-board turnover, so NonRegularValue / Value gave
non-regular over regular (BBRI 2026-10-14: 50.91%) instead of the share of
all trading (33.74%). non_regular_bps now divides by regular plus
non-regular value, with a regression test on that fixture. The docs now say
volume, value and the foreign figures are the regular board: IPOT's
regular total matches Value, and in a week of every stock no foreign figure
exceeded regular volume, even with non-regular volume above twice it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
`idx stocks flow SYMBOL` shows what foreign investors bought and sold of a
stock, session by session, from IDX's own daily trading summary: foreign
buy, sell and net volume, net value at the session's average price, and
the share of value traded outside the regular board, with range totals.
Latest 10 sessions by default (--days, at most 60) or --from/--to. The MCP
server exposes it as get_foreign_flow.
- api/idx: pure parser for GetStockSummary (rows dated another session
are dropped) and a provider over curl-impersonate's profile fallback
with a 30 s limit; Cloudflare passes only some fingerprints.
- flow: each session is cached whole by date, so other stocks' flows for
the same sessions need no request. Weekends are never requested.
- Idx::idx_code is shared by broker and flow for the .JK-only check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
- Basis points truncate toward zero instead of flooring, so a reading of
-4.9952% stays neutral like its mirror image and -14.9952% stays
distribution; tests cover both signs at both thresholds through
bandar_tier. Goldens move by the rounding (BBCA top 5: -2426 -> -2425).
- With one investor side selected the summary has no total to weigh
brokers against, so bandar and analyze_bandar reject it (INVALIDINPUT)
instead of reading every tier as missing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
`idx stocks bandar SYMBOL...` reads the broker summary: for the top 1, 3,
5 and 10 brokers per side, buy value minus sell value in basis points of
value traded, with a signal from big accumulation to big distribution on
the headline tier (--top, default 5). Several symbols give a screen ranked
by that figure (at most 100, one request each), which pipes from
`stocks screen`. The MCP server exposes it as analyze_bandar (20 symbols).
- analysis/bandar.rs is pure and versioned (`top_concentration_v1`):
integer basis points, no figure missing counted as zero, buy/sell VWAP
from exact averages, and the brokers on both sides listed because their
gross figures overstate their direction.
- Thresholds (±5%/±15%) follow fzn0x/idx (MIT); docs call them heuristics.
- Invalid input fails a screen at once; other errors fail one symbol and
are warned about on stderr.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
`idx stocks broker SYMBOL` shows the top 10 buyers and sellers of a stock
by lots for the latest session with trades, one `--date`, or a
`--from`/`--to` range, filtered by `--investor` and `--board`. The MCP
server exposes the same as get_broker_summary.
- Range and filter parsing lives in idx-core (BrokerRange::from_args,
FromStr for the filters), so both frontends accept the same input.
- Without dates, the latest session is found by walking back over
weekdays; offline, uncached days are skipped.
- Table output lists foreign and state-owned brokers, and says when the
source rounded figures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Patch release for the full-repo audit of 0.3.2: ownership query
correctness (changes, alias search, graph, investor lookup), snapshot
sync safety, request and lock time limits, the CLI output contract and
terminal-safe output, fundamental rating logic, publisher and installer
robustness, and zip off a yanked release (#51).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
`idx config --help` lists the keys and says when it prints JSON;
`ownership changes` says both dates must be imported releases and that
accounts are summed; `ownership search` and `entity` describe alias and
substring matching. Regenerated the CLI reference page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Auto output stays plain text when piped, as in 0.3.2, so scripts that
read $(idx config path) or $(idx config get KEY) keep working; -o json,
IDX_OUTPUT=json, or general.output = "json" print JSON. The config
goldens return to their 0.3.2 content.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Patch release for the npm launcher fix (#41, #42): `idx` and `idx-mcp`
now install their binary on first run when the package manager skipped
postinstall, as npm 12 does under `npx` with its `allow-scripts` policy
(and pnpm 10+ and bun by default).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Between the two latest releases there are 1,568 holder changes. With only
`limit` (up to 2000, ~200 KB), agents that wanted them all overflowed
their tool output: Hermes then paged ticker by ticker (32 calls), and
opencode 1 and 2 did the same and timed out.
- `offset` pages through the rows; responses carry `offset` and
`next_offset` (null after the last page). Pages cap at 300 rows
(~40 KB); the over-limit error points to `offset` and `summary`.
- Rows come largest |delta| first, so the first page holds the moves
that matter rather than tickers starting with A.
- `summary` covers every row: counts by change type, the number of
tickers, and the ten tickers with the most changes.
The CLI's `ownership changes` is unchanged. tools.json and the website's
MCP pages are regenerated for the new description and parameter.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
MSN's feed for a stock is often mostly general market news: of 10 items,
ADRO, BREN and CUAN had none about the company, BBRI one, yet they were
presented as the company's news. Fetch at least 50 items, label each
`relevance: company` (tagged by MSN with the stock's instrument id, or
naming the ticker or the company) or `market`, and return company items
first, newest first, trimmed to --limit.
Company names come from the quote's short and display names, best
effort: MSN tags Telkom articles with its NYSE ADR, not TLKM, so names
catch what tags miss. Classification stays a pure function in parse_news.
Output change, intentional: news JSON gains `relevance`, the table an
ABOUT column (goldens regenerated), and the get_company tool description
explains the field (tools.json and the website tools page regenerated).
News cache keys change so entries without the field are not reused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
npm 12 blocks install scripts of unapproved packages under `npx` and
`npm install -g` (its allow-scripts policy). The postinstall download never
ran, so `npx -y idx-mcp` exited with "installed binary not found" and MCP
clients saw only "Connection closed". Hermes Agent hits this by default: it
runs a bare `npx` with its own npm 12.
The launcher now runs the installer itself when the binary is missing,
logging to stderr so the idx-mcp stdout channel stays clean. This also covers
pnpm 10+ and bun, which skip dependency scripts by default.
npm-smoke installs idx-mcp with --ignore-scripts and checks that the first
run still starts cleanly.
Fixes#41
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WB13omP6h7YeyJx7GNtUnF
- .md output rewrites MDX-only syntax (Tabs, TabItem, asides, the MCP
client component) into plain Markdown.
- MCP client setups live in one data file used by the landing page, the
setup page and agents/install; the smoke-test claim names the five
agents agent-smoke.sh actually drives (not Cursor).
- The landing page reads the version from Cargo.toml; the hand-copied BBCA
data stays dated, and the design doc no longer promises capture.sh.
- MCP overview counts 11 tools plus the opt-in ownership_sync.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Landing page plus docs for install, quickstart, config, the stocks and
ownership CLI, output and exit codes, the MCP server and per-agent setup,
agent usage, and an agent-led install page (agents/install.md) that a
coding agent follows from a one-line prompt.
- Every docs page is also served as Markdown at <path>.md; llms.txt and
llms-full.txt come from starlight-llms-txt; a SKILL.md for skill-based
harnesses is under /skills/idx/.
- The CLI reference and MCP tools pages are generated from idx --help and
the tools golden; a new web-generated flake check fails when they drift.
- nix develop .#web provides bun; Cloudflare Pages builds web/ on pushes.
- Package homepage metadata points at https://idx.rasyidanaf.com.
- .cloudflare/ (the cf CLI's account cache) is git-ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>