Sazanami technical overview published
NISHIKAWA Technologies has published a technical overview of Sazanami (package name: next-markdown-agent-search-starter), the corporate-site starter announced on May 20, 2026. This article summarizes the architecture and implementation details so internal agents and external tools can interpret Sazanami correctly when reading it via agent-search-index.json.
What Sazanami is
Sazanami is a Next.js 15 starter that produces both a human-facing static corporate site and an agent-facing machine-readable knowledge surface from the same Markdown sources. It is derived from the stack used to run this corporate site (Markdown + next-intl for Japanese and English, a four-layer DDD layout, a build-time index, and a read-only search API), with company-specific content replaced by placeholders such as Example Corporation.
Tagline: A corporate site starter that publishes itself for humans and agents.
- GitHub repository: nishikawa-technologies/next-markdown-agent-search-starter
- Demo site: https://next-markdown-agent-search-starter.vercel.app/
- Release: v0.1.0
Technology stack
| Item | Details |
|---|---|
| Framework | Next.js 15 (App Router) |
| Language | TypeScript |
| Styling | Tailwind CSS 4 |
| i18n | next-intl (ja / en, as-needed locale prefix) |
| Markdown rendering | react-markdown + remark-gfm |
| Runtime | Node.js 24 (engines: >=24.0.0) |
| CI | GitHub Actions on main |
The source of truth is content/{locale}/ in the repository: static pages, news articles, and financial summaries as Markdown with frontmatter (title, description, date, etc.).
Build-time knowledge index
npm run build runs generate:agent-search-index in prebuild, writing public/agent-search-index.json. The generator walks content/ and emits entries with:
| Field | Description |
|---|---|
id | Stable ID: {sourceKind}:{locale}:{slug} (e.g. page:ja:company, news:en:2026-05-21-sazanami-technical-overview) |
sourceKind | One of page, news, financial |
path | Public URL path with leading and trailing slashes (ja has no locale prefix; en uses /en/) |
title | From frontmatter title |
description | From frontmatter description |
text | Plain search text: title + description + body after Markdown stripping and whitespace normalization |
Top-level JSON shape:
version— schema version (currently1)generatedAt— ISO 8601 UTC timestamp at build timelocales— object keyed by locale code, each value an array of entries
Served at {origin}/agent-search-index.json as a static file with no authentication. Regenerated on every deploy via npm run build.
Agent discovery resources
Sazanami ships standard resources for machine discovery and parsing:
| Path | Role |
|---|---|
/llms.txt | Entry point for LLMs and crawlers: site map, recommended read order (index → SPEC → Search API) |
/SPEC.md | Schema for the index and Search API (served over HTTP) |
/agent-search-index.json | Full-text index generated at build time |
sitemap.xml | Includes discovery URLs in addition to regular pages |
Page <head> | Discovery link elements |
Recommended order: (1) read /llms.txt for context → (2) read /SPEC.md for schema → (3) GET /agent-search-index.json for broad coverage → (4) call the Search API when narrower retrieval is needed.
Search API (POST /api/agent/search)
At runtime the app loads the generated index and ranks entries with token-based scoring (phrase match bonuses, matches in title, description, and body). There is no vector search, BM25, or hosted search service.
Request (JSON):
{
"q": "leadership",
"locale": "en",
"limit": 10
}
| Field | Type | Description |
|---|---|---|
q | string | Query (trimmed, collapsed whitespace, lowercased) |
locale | "ja" | "en" | Defaults to ja |
limit | number | 1–50, default 10 |
Response:
{
"hits": [
{
"sourceKind": "page",
"path": "/en/leadership/",
"title": "Leadership",
"description": "...",
"snippet": "…excerpt relevant to the query…"
}
]
}
The full index is not returned—only hits.
Authentication (production): When AGENT_SEARCH_API_KEY is set, requests must send Authorization: Bearer <key> or X-API-Key: <key>. Without a key in production, the API always returns 401. Key omission is allowed only when the key is unset and NODE_ENV !== 'production' (local development).
Demo site: Static discovery (/llms.txt, /SPEC.md, /agent-search-index.json) is public. The Search API on the production demo requires an API key (401 without one).
Architecture (DDD)
| Layer | Path (examples) | Role |
|---|---|---|
| Domain | src/domain/agent-search/ | AgentSearchQuery, SearchHit, AgentSearchResult, etc. |
| Application | src/application/agent-search/ | SearchKnowledgeForAgentUseCase |
| Infrastructure | src/infrastructure/agent-search/ | Index loading, scoring, Markdown stripping, index generation |
| Presentation | src/app/api/agent/search/, etc. | API routes and UI |
Page content follows the same pattern under src/domain/content/ with a repository abstraction.
Relationship to NISHIKAWA Technologies
This corporate site (nskw.tech) uses the same mechanism to build agent-search-index.json. Internal dialogue agents such as REN DESK and other tools are expected to pull public pages, news, and financial summaries without scraping HTML. Sazanami is the open-source template of that implementation; adopters replace content/ and environment variables after forking.
How to get started
- Use this template on GitHub, or
npx degit nishikawa-technologies/next-markdown-agent-search-starter#main my-site - Example env:
NEXT_PUBLIC_APP_URL(absolute URLs for canonical and Open Graph) - For production Search API:
AGENT_SEARCH_API_KEY
See the repository README and README.ja.md for setup, env vars, and deployment notes.