Skip to content

feat(site): improve agent readiness - #20

Merged
channprj merged 8 commits into
mainfrom
feat/agent-readiness-20260824
Aug 23, 2026
Merged

channprj merged 8 commits into
mainfrom
feat/agent-readiness-20260824

Conversation

@channprj

@channprj channprj commented Aug 23, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • restore Pages deployments after version changes and shallow checkouts
  • serve meaningful prerendered HTML at canonical and legacy paths, with hydration-safe alias routing and recovery-oriented 404 content
  • publish llms.txt v2 guidance, sitemap/robots rules, and 44 Markdown page alternates
  • add localized About, Contact, Privacy, and developer trust resources
  • add SoftwareApplication and Organization JSON-LD from public maintainer facts

Verification

  • Node 22.22.0 npm test: Vitest 53 passed, Node 18 passed, typecheck/build passed
  • exact remote depth-1 clone at 711b1fa: full suite passed
  • GitHub CI at 711b1fa: success
  • 44 prerendered HTML pages, 44 Markdown siblings, 44 sitemap URLs
  • 12/12 localized About/Contact/Privacy pages: >=500 visible characters (minimum 698)
  • hydrated compatibility paths ko/usage, en/openclaw, ko/openclaw: correct H1/title, no ErrorBoundary
  • 61 generated HTML files, 2,247 internal references, missing 0
  • git diff --check

Review remediation

  • fixed shallow-history lastmod and VERSION-only Pages trigger findings
  • fixed compatibility pages turning into ErrorBoundary after hydration
  • expanded Japanese and Chinese privacy trust anchors past the 500-character contract
  • latest Codex review of 711b1fa reported no suggestions

Explicit hosting constraints

GitHub Pages cannot provide request-time Accept: text/markdown negotiation, Vary: Accept, or a Streamable HTTP MCP POST endpoint. This PR publishes standards-based Markdown alternates and documents the native stdio MCP server without claiming unsupported HTTP behavior.

Copilot AI lite review requested due to automatic review settings August 23, 2026 21:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Several lastModified values are set to a future date (2026-08-24) relative to the PR timestamp, which will surface as incorrect “updated” UI and sitemap metadata.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR enhances the kmsg documentation site’s “agent readiness” by expanding the localized route set, publishing Markdown alternates alongside prerendered HTML (including legacy aliases), adding trust/developer resources pages, and embedding homepage JSON-LD for SoftwareApplication + Organization metadata.

Changes:

  • Expanded the localized canonical route table from 32 → 44 pages and added new “Developers / About / Contact” content across ko/en/jp/cn.
  • Updated the static build pipeline to emit index.md Markdown alternates for canonical pages and serve legacy aliases as full prerendered pages (no meta refresh).
  • Added homepage JSON-LD structured data and tightened site build tests to assert substantive prerendered HTML, sitemap integrity, robots/llms discovery, and Markdown artifacts.
File summaries
File Description
site/test/routes.test.ts Updates route-count expectations and adds locale target coverage for new pages.
site/test/metadata.test.ts Adds test coverage for homepage JSON-LD structured data graph.
site/test/markdown-content.test.mjs Updates expected synced Markdown entry count for expanded docs set.
site/test/build.test.mjs Expands build artifact assertions for Markdown alternates, legacy aliases, SEO/meta contracts, and structured data.
site/scripts/sync-markdown-content.mjs Syncs additional Markdown-backed pages and merges trust content into document content generation.
site/scripts/build-static.mjs Writes Markdown alternates, copies prerender output for legacy aliases, enriches 404 recovery content, and updates discovery files.
site/content/ko/developers.md Adds localized developer resources page (Korean).
site/content/ko/contact.md Adds localized contact/support page (Korean).
site/content/ko/about.md Adds localized about/trust page (Korean).
site/content/jp/developers.md Adds localized developer resources page (Japanese).
site/content/jp/contact.md Adds localized contact/support page (Japanese).
site/content/jp/about.md Adds localized about/trust page (Japanese).
site/content/en/developers.md Adds localized developer resources page (English).
site/content/en/contact.md Adds localized contact/support page (English).
site/content/en/about.md Adds localized about/trust page (English).
site/content/cn/developers.md Adds localized developer resources page (Chinese).
site/content/cn/contact.md Adds localized contact/support page (Chinese).
site/content/cn/about.md Adds localized about/trust page (Chinese).
site/app/root.tsx Adds Markdown alternate <link> and injects homepage JSON-LD; updates discovery link relationship.
site/app/lib/metadata.ts Introduces homepageStructuredData() JSON-LD graph and keeps per-page metadata behavior intact.
site/app/content/trust-content.json Adds new trust/developer page copy with explicit lastModified metadata.
site/app/content/routes.ts Extends PAGE_KEYS and slug mappings for new pages.
site/app/content/pages.ts Merges trust content with legacy content for page copy lookup.
site/app/content/legacy-content.json Updates privacy copy to reflect expanded data-boundary and reporting guidance.
site/app/content/document-content.json Adds generated document entries for new pages and updates some last-modified timestamps.
site/app/components/site-footer.tsx Adds footer navigation links for new trust/developer resources pages.
site/app/components/mobile-navigation.tsx Adds mobile nav entry for the Developers page.
Review details
  • Files reviewed: 26/27 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

private func filterMessagesAfterWatchStart(_ messages: [TranscriptMessage], watchStartedAt: Date) -> [TranscriptMessage] {
messages.filter { message in
guard let logicalTimestamp = message.logicalTimestamp else {
return false
}
return logicalTimestamp > watchStartedAt
}

P1 Badge Keep same-minute messages in the watch stream

When a watch starts at 12:34:30, KakaoTalk's minute-resolution label gives a new 12:34 message a logical timestamp of 12:34:00, so this comparison rejects every message received during the rest of that minute; messages without a parseable timestamp are also rejected unconditionally. As a result, watch can silently miss genuinely new messages and should use the stabilized baseline rather than a strict second-resolution cutoff.


guard !previousMessages.isEmpty else {
previousMessages = currentMessages
return []

P1 Badge Emit the first event after an empty baseline

When stabilization completes before any post-start message arrives, replaceBaseline initializes this state with an empty array. The first later message then enters this branch, is stored as the new baseline, and is returned as no events, so the first message after starting a normal watch is permanently swallowed. Track initialization separately from whether the initialized baseline happens to be empty.


if let existingWindow = findMatchingChatWindow(in: kakao.windows, query: query) {
standardizeReadableWindow(existingWindow, label: "existing chat window")
return ChatWindowResolution(window: existingWindow, method: .existingWindow)

P1 Badge Resolve chat IDs before matching windows by display name

When two chats share the same display name and either one already has an open window, resolve(chatID:) returns the first title match without consulting which registry ID was requested. Consequently, send --chat-id or read --chat-id can operate on the wrong conversation; the ID-specific chat-list resolution must take precedence whenever the name is ambiguous.


let storedCredentials = try store.loadCredentials()
let credentials = try storedCredentials ?? PasswordPrompt.promptForCredentials(defaultIdentifier: store.storedIdentifier())
guard let form = findLoginForm() else {

P1 Badge Refuse interactive credential prompts without a TTY

When an automatic command runs logged out with no saved credentials, this path prompts without checking PasswordPrompt.canPrompt. In mcp-server, the child command inherits the server's protocol stdin, so it can block until timeout or consume subsequent JSON-RPC bytes as the username/password; cron and other noninteractive callers similarly hang. Return an actionable authentication error unless a terminal is attached.


for message in messages {
let key = messageFingerprint(message)
if seen.contains(key) { continue }
seen.insert(key)
unique.append(message)

P1 Badge Preserve repeated messages in transcript results

For two legitimate messages with the same author, displayed minute, and body—for example, sending OK twice within one minute—messageFingerprint produces the same key and this loop drops the second message. The fingerprint also omits the message date and media counts, so identical text at the same time on different days or distinct attachments can collapse as well, making read and watch return an inaccurate transcript.


- name: Checkout
uses: actions/checkout@v7

P1 Badge Fetch history before deriving document timestamps

The Pages workflow uses checkout's one-commit default, but both site generation scripts derive unpinned document dates with git log -1 -- <source>. On a later site-only change where a documentation source is not modified in the shallow HEAD, that command returns an empty string; prerendering then formats an invalid date and the sitemap test rejects the empty <lastmod>, blocking deployment. Fetch sufficient history here or make timestamp generation handle an empty result.


- "USAGE.md"
- "ARCHITECTURE.md"
- "VERSIONING.md"
- "docs/openclaw.md"

P2 Badge Trigger Pages when VERSION changes

The documented release bump creates a commit that changes only VERSION, but this Pages path filter omits that file even though site/scripts/build-static.mjs reads it to publish the current version in llms.txt. Normal release pushes therefore skip the Pages workflow and leave the public agent-facing version stale until an unrelated site or documentation change is deployed.

AGENTS.md reference: AGENTS.md:L66-L66

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@channprj

Copy link
Copy Markdown
Owner Author

@codex review

Please review current head 7ff2576. The site-specific shallow-history and VERSION-trigger findings from the prior review were fixed in 7ff2576 and verified with a real depth-1 clone. Findings against unchanged Sources/kmsg/** are pre-existing outside this site-only diff (4c8ab79..HEAD).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ff2576c20

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const target = `${baseUrl}${page.publicPath}`
const legacyPath = `ko/${pageSlugs[page.pageKey]}index.html`
await write(legacyPath, redirectDocument(target, "ko"))
await copyOutput(`${page.publicPath}index.html`, legacyPath)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep copied aliases from hydrating into 404s

When a browser opens a copied Korean alias such as /kmsg/ko/usage/, this serves the canonical page together with its client bundle, but after hydration routeFromPath() cannot resolve /ko/usage/ because Korean canonical routes omit the ko segment, so PageRoute throws its 404 response and replaces the initially valid page. The copied openclaw aliases have the same problem because the router only recognizes mcp; either retain redirects or explicitly normalize these compatibility routes before hydration.

Useful? React with 👍 / 👎.


## MCP server

The [MCP guide](../mcp/) documents `kmsg mcp-server`, a stdio server exposing `kmsg_read`, `kmsg_send`, and `kmsg_send_image`. Clients launch the installed binary and exchange JSON-RPC through standard input and output. kmsg currently has no first-party Streamable HTTP MCP endpoint or live `/.well-known/mcp` handshake; a static GitHub Pages response cannot represent a POST-based MCP session.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Map the public MCP slug before rendering developer links

On every localized developer page, this ../mcp/ target is passed through resolveMarkdownTarget(), whose markdownPageKey() recognizes openclaw but not mcp. Consequently the generated HTML links to https://github.com/channprj/kmsg/blob/main/site/content/mcp/, a nonexistent repository path, instead of the localized /kmsg/<locale>/mcp/ page. Recognize mcp as the openclaw document key or use the source filename in these links.

Useful? React with 👍 / 👎.

Comment on lines +63 to +64
const markdown = await readFile(resolve(repoDir, page.source), "utf8")
return markdown.endsWith("\n") ? markdown : `${markdown}\n`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Rewrite repository-relative links in published Markdown

When an agent follows one of the new index.md links from llms.txt, the source document is copied verbatim, so repository-relative links no longer point to the published layout. For example, /kmsg/index.md contains links such as USAGE.md, ARCHITECTURE.md, and LICENSE; these resolve under /kmsg/ to files that are not emitted, while the available pages are /kmsg/usage/index.md and /kmsg/architecture/index.md. Transform relative links for the static Markdown location, as the HTML content pipeline already does, or link them back to repository sources.

Useful? React with 👍 / 👎.

@channprj

Copy link
Copy Markdown
Owner Author

@codex review

Please re-review current head 711b1fa. It closes the compatibility-page hydration finding by canonicalizing published aliases in routeFromPath, and expands/tests all 12 localized About/Contact/Privacy pages to at least 500 visible characters. Please limit findings to the site diff from 4c8ab79..HEAD.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 711b1fa106

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


## Events and webhooks

Run `kmsg watch --json` as a local process for newline-delimited message events. kmsg does not operate a hosted webhook delivery or callback registration service. If a workflow needs webhooks, an operator-owned supervisor must validate local events, apply approval policy, and deliver them to an endpoint the operator controls.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Correct the advertised JSON event framing

Consumers following this developer page will treat each line from kmsg watch --json as a complete JSON event, but WatchCommand.emitJSON() uses JSONEncoder with .prettyPrinted and then writes two newlines, so a single event spans many lines. A line-oriented supervisor will therefore attempt to parse fragments such as { and fail; either emit compact one-object-per-line JSON or document the output as a whitespace-separated stream of pretty-printed JSON values.

Useful? React with 👍 / 👎.

@channprj
channprj merged commit a5a66de into main Aug 23, 2026
1 check passed
@channprj
channprj deleted the feat/agent-readiness-20260824 branch August 23, 2026 21:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants