National Diet Minutes Search Skill
Investigates Japanese National Diet minutes from the start of the Diet (1947) onward via the NDL (National Diet Library) Minutes Search System API. No authentication required. Invoked using bash scripts/<script>.sh wrapper.
Imperial Diet minutes (up to 1947) are handled by a separate API and are not covered.
Basic Rules
- Base URL:
https://kokkai.ndl.go.jp/api/ - Response format:
recordPacking=json(always enforced by wrapper scripts) - Authentication: Not required
- Invocation method: Use
bash scripts/<script>.sh. Direct use ofWebFetch/Invoke-RestMethodetc. is only for corner cases not covered by the wrapper (see "Cases requiring raw curl" below) - Rate limit: The official documentation states "mechanical access must avoid multiple requests; leave intervals of several seconds." Parallelization is prohibited; sequential calls should be spaced 2–3 seconds apart.
- Query length limit: 2,000 bytes (Japanese characters are approximately 9 bytes each when URL-encoded)
Endpoint Selection
Select the appropriate wrapper script based on user requests. The amount of information and token consumption increases in the order list-meetings.sh < search-by-*.sh < fetch-meeting.sh, so progressively narrow down from lighter options.
"Show me statements made by Member ○○"
→ bash scripts/search-by-speaker.sh ○○ [from] [until] [limit] --sort <keys>
※ `--sort` is required. Representative value: `date-desc` (newest first)
"Search for statements about △△"
→ bash scripts/search-by-keyword.sh △△ [from] [until] [limit] --sort <keys>
※ `any` search (AND). Multiple keywords separated by spaces. `--sort` required.
"Extract witness questioning (including references and public commenters)"
→ bash scripts/search-by-role.sh 参考人 [from] [until] [limit] --sort <keys>
※ `role` is one of: 証人 / 参考人 / 公述人. `--sort` required.
"Show me a list of meetings for Committee ○○"
→ bash scripts/list-meetings.sh ○○ [from] [until] [limit] --sort <keys>
※ Lightweight. Only returns meeting metadata (no speech text). `--sort` required (only `date-asc` / `date-desc`).
"Show me all statements for a specific meeting" / "Full minutes of Committee ○○ on YYYY-MM-DD"
→ Step 1: Use `bash scripts/list-meetings.sh` to identify the target meeting's `issueID`
→ Step 2: Use `bash scripts/fetch-meeting.sh <issueID>`
※ Returns the full meeting in a single request, so it can be large. Always narrow down first.
See api-reference.md, parameters.md, response-format.md, recipes.md for details.
Usage of Each Endpoint
1. search-by-speaker.sh — Search statements by member name (most frequent)
Returns only statements matching the search conditions. Most token-efficient. --sort is required, making the user explicitly aware of the API sort order specification (countermeasure #41).
# Extract statements by member name (partial match OR), descending by date
bash scripts/search-by-speaker.sh 岸田文雄 2024-01-01 2024-12-31 50 --sort date-desc
See bash scripts/search-by-speaker.sh -h for full argument specifications (including details on possible sort keys).
The response is a speechRecord[] array. Each element contains meeting metadata (issueID, session, nameOfHouse, nameOfMeeting, date, etc.) flattened.
2. search-by-keyword.sh — Keyword search (any search, AND)
Full-text search of speech text. Multiple keywords are AND-joined separated by spaces. --sort required.
# AND search: statements containing both "マイナンバー" and "個人情報", descending by date
bash scripts/search-by-keyword.sh 'マイナンバー 個人情報' 2024-01-01 2024-12-31 50 --sort date-desc
See bash scripts/search-by-keyword.sh -h for full argument specifications. Response structure is identical to search-by-speaker.sh.
3. search-by-role.sh — Search statements by role (e.g., witness questioning)
Filters by the speaker's role (speakerRole). Used to extract witness questioning, reference statements, and public commenter statements. --sort required.
# Only reference statements, descending by date
bash scripts/search-by-role.sh 参考人 2024-01-01 2024-12-31 50 --sort date-desc
role must be one of: 証人 (witness) / 参考人 (reference) / 公述人 (public commenter). Specifying anything else will cause the API to reject with HTTP 400.
See bash scripts/search-by-role.sh -h for full argument specifications.
4. list-meetings.sh — Meeting list (lightweight index)
Returns only meeting metadata. Does not include speech text, making it suitable for generating lists and narrowing down. Used to identify issueID. --sort required (only date-asc / date-desc).
# List of Budget Committee meetings for a specific day, ascending by date
bash scripts/list-meetings.sh 予算委員会 2024-03-01 2024-03-31 50 --sort date-asc
See bash scripts/list-meetings.sh -h for full argument specifications.
The response is a meetingRecord[] array. The speechRecord[] under each element contains only the minimum set of speech metadata (speechID, speechOrder, speaker, speechURL). To get the full text, call search-by-* or fetch-meeting.sh.
5. fetch-meeting.sh — Full meeting text (last resort)
Returns the full text of a meeting. Heavy because it returns all statements in a single request. Call after identifying the issueID via list-meetings.sh.
# Fetch full meeting by issueID
bash scripts/fetch-meeting.sh 121405254X00220241004
See bash scripts/fetch-meeting.sh -h for argument specifications. maximumRecords is fixed at 1 (since issueID is unique). --sort is not applicable because it retrieves a single meeting (use jq for post-processing of output if needed).
fetch-meeting.sh's speechRecord[] contains all fields (speech, speakerYomi, speakerGroup, speakerPosition, speakerRole, startPage, createTime/updateTime).
Token Saving Guidance
bash scripts/fetch-meeting.sh can be several hundred KB to MB per meeting. Follow these rules:
- Prefer
search-by-*.sh: For speech units, it retrieves only the necessary parts.bash scripts/fetch-meeting.shshould be used only when the user explicitly requests a "full meeting text." - Explicitly specify
maximumRecords: The default of 30 is sufficient in many cases; can be omitted. When retrieving many records, increase up to the limit (search-by-*/list-meetings: 100, fetch-meeting: 10) to reduce the total number of requests. - Use two-stage search: First narrow down with
list-meetings.shorsearch-by-*.shto get theissueID, then if needed, usefetch-meeting.shfor the full text. Do not callfetch-meeting.shfrom the start. - Retry with variations on 0 hits: For member names, try
福島 みずほ/福島瑞穂/ hiragana sequentially. For group names, always use the full official name (自民党❌ /自由民主党✅).
Pitfalls in Result Filtering
After receiving the response, note the following:
- Rows with
speechOrder=0are meeting record headers: Structural information such as agenda, items for deliberation, etc., not actual statements. Thespeakeris fixed as会議録情報. Exclude rows wherespeechOrderis0when aggregating statements. - Values of
imageKind: By default, besides会議録(minutes),目次(table of contents),索引(index),附録(appendix), and追録(supplement) may be mixed in. When extracting statements, filter to rows whereimageKindis会議録. The request parameterscontentsAndIndexandsupplementAndAppendixboth default tofalse, so they can usually be omitted. Specifytrueonly if you explicitly want to include them. closingreturnsnullinstead offalse: For regular sessions without a closed session flag, it returnsnull. Determine if it is a closed session review only whenclosingistrue(compare withtrue, not withfalse).- Invalid values in
nameOfHouseare silently ignored: The API returns HTTP 200 with results where the filter was not applied. Verify that the intent was reflected by checking the validity ofnumberOfRecords. - Line breaks in speech text are CRLF (
\r\n): Not just LF. Normalization may be necessary during text processing. - Response structure of
search-by-*.shis flat: Does not have ameetingRecordwrapper likefetch-meeting.sh. Branching is needed if writing a common parser. - API sort order is fixed as "descending by meeting date": The official specification guarantees descending order, and there is no sort parameter on the API side (same for search-by-speaker, search-by-keyword, list-meetings, and fetch-meeting). The
--sortparameter in this skill's wrapper scripts is not an API parameter but a client-side sort post-processing viajq(required insearch-by-*.sh/list-meetings.sh). While convenient, when usingmaximumRecordsfor partial retrieval, only the most recent N items are returned.- Determining the latest statement: OK as the first item of a partial retrieval (
maximumRecords=1is sufficient). - Determining the oldest statement: Do not determine from a partial retrieval result. Either retrieve all items via pagination to the end of
numberOfRecords, or narrow down the period usingfrom/untiluntil the hit count ≤maximumRecordsbefore determining. - Secondary sort within the same day is ascending by
speechOrder(measured, not in official specification): If you hit the tail directly withstartRecord=<numberOfRecords>&maximumRecords=1without narrowing the period, due to fixed descending order, you will get the last statement of the oldest date within the period (maxspeechOrder), missing the true first statement. Narrow the period usingfrom/untiluntilnumberOfRecords ≤ 100, retrieve all, and confirm with a single request using--sort date-asc,speech-order-asc(see recipes/oldest-speech-by-speaker.md for details).
- Determining the latest statement: OK as the first item of a partial retrieval (
- Combining
anyandspeakerresults in an intersection (significantly fewer results): If you specify bothany=A&speaker=Ato search for statements by Member A, only statements satisfying both conditions (Member A speaking while including their own name) are returned, which is far fewer than either alone (measured:speaker=石原慎太郎alone: 2,098 items / combined: 647 items). Usespeakeralone for all statements by Member A, andanyalone for references to A. For usage by intent, see the relevant section in parameters.md and recipes/speaker-vs-any-disambiguation.md. (19004)startRecord out of rangerefers tonumberOfRecordsof the same query: The error message(19004)startRecord には 1 から検索件数までの値を指定してください。means that the "number of search results" refers tonumberOfRecordsfrom the same query (measured, not explicitly in official specification). DeterminingstartRecordfrom another query (simple search withoutfrom/until,speakeralone vs combined, previously cached values) will trigger error 19004. To isolate the cause, send a single request withstartRecord=1&maximumRecords=1using the same query and re-checknumberOfRecords. This frequently occurs in cases of intersection (item 8) or when addingfrom/untilreduces the count (see api-reference.md's 19004 explanation for details).
Common Search Pattern Examples
Statements by a member within a specific period
bash scripts/search-by-speaker.sh 石破茂 2024-10-01 2024-10-31 100 --sort date-desc
Tracking bill deliberation (chronological)
bash scripts/search-by-keyword.sh マイナンバー法 2023-01-01 '' 100 --sort date-asc
Extracting Prime Minister's speeches
The speakerPosition argument is not supported by the wrapper, so use raw curl:
# Not supported by wrapper; use raw curl
curl -s 'https://kokkai.ndl.go.jp/api/speech?speakerPosition=%E5%86%85%E9%96%A3%E7%B7%8F%E7%90%86%E5%A4%A7%E8%87%A3&nameOfMeeting=%E6%9C%AC%E4%BC%9A%E8%AD%B0&from=2024-01-01&recordPacking=json'
Witness questioning
bash scripts/search-by-role.sh 参考人 2024-01-01 '' 100 --sort date-desc
Full minutes of a specific meeting (two-stage)
# Step 1: Identify issueID (nameOfHouse filter not supported by wrapper; manually select from the list)
bash scripts/list-meetings.sh 予算委員会 2024-03-01 2024-03-01 50 --sort date-desc
# Step 2: Fetch full text
bash scripts/fetch-meeting.sh <issueID>
Pagination
Common to all endpoints.
- Pass
nextRecordPositionfrom the response asstartRecordfor the next request - Determining the last page:
- JSON:
nextRecordPositionvalue isnull - XML: The
<nextRecordPosition>element itself is absent
- JSON:
- Leave intervals of several seconds for sequential retrieval (rate limit)
Output Format
Recommended format when presenting statements to the user:
【Speaker】○○○○ (Affiliated faction / Title)
【Meeting】XXXth Diet, House of ○○, ○○ Committee, No. X (YYYY-MM-DD)
【Statement】
Quotation of the speech text (normalize CRLF to line breaks)
【Source】National Diet Minutes Search System https://kokkai.ndl.go.jp/txt/<issueID>/<speechOrder>
When presenting a meeting list:
【Meeting List】N items
- YYYY-MM-DD: XXXth Diet, House of ○○, ○○ Committee, No. X
https://kokkai.ndl.go.jp/txt/<issueID>
- ...
Cases Requiring Raw curl
The following parameters are not covered by wrapper scripts. When needed, call the API directly with curl / Invoke-RestMethod:
sessionFrom/sessionTo(session number filter)contentsAndIndex/supplementAndAppendix(table of contents, index, appendix)closing=true(closed session review only)- Secondary filters like
nameOfHouse/nameOfMeeting(not included in wrapper arguments) - Pagination (sequential calls with
startRecord+nextRecordPosition) - Simultaneous specification of
anyandspeaker(for intentional intersection, e.g., self-reference by a member; see recipes/speaker-vs-any-disambiguation.md pattern 3)
Example: Extracting only Budget Committee meetings from the 213th Diet (requires sessionFrom/sessionTo, not supported by wrapper)
curl -s 'https://kokkai.ndl.go.jp/api/meeting_list?sessionFrom=213&sessionTo=213&nameOfMeeting=%E4%BA%88%E7%AE%97%E5%A7%94%E5%93%A1%E4%BC%9A&maximumRecords=30&recordPacking=json'
Tools that interpose an internal summarization model (e.g., WebFetch) have been observed to hallucinate fields not present in the response. Do not use them for raw data acquisition (see response-format.md for details).
Detailed References
- api-reference.md: Endpoint specifications, pagination, error responses
- parameters.md: Full specification of search parameters, search methods, combination examples
- response-format.md: Response structure, actual JSON samples, measured pitfalls
- recipes.md: Complex pattern collection (member × keyword filter, etc., cases not covered by scripts)