Skip to content

Rebuild kwt.sh as a product, guide, and docs site - #129

Open
wesm wants to merge 6 commits into
mainfrom
site/tiered-marketing
Open

Rebuild kwt.sh as a product, guide, and docs site#129
wesm wants to merge 6 commits into
mainfrom
site/tiered-marketing

Conversation

@wesm

@wesm wesm commented Sep 5, 2026

Copy link
Copy Markdown
Member

kwt.sh becomes a three-tier site: a hand-written product page at /, a guide at /guide/, and the Zensical documentation moved under /docs/. Before this, the Zensical build was the whole site, so the first thing a visitor saw was the docs index rather than what kwt is for. The docs tier is cut back to technical reference for people and their agents, with /llms.txt indexing every page and a Markdown twin (/page.md) served beside every rendered /page/.

The dashboard on the product page is a real capture, not a drawing. make docs-screenshot runs docs/screenshots/generate-tui.sh, which builds kwt, seeds two disposable repositories with dirty, ahead, behind, and live worktrees, runs kwt tui inside a private tmux server, and renders the pane to docs/website/assets/dashboard.svg with freeze. The fixture uses its own KWT_HOME, TMUX_TMPDIR, and Git config, and launches the TUI with a scratch HOME so it never adopts the operator's own projects. Commit dates and file times are relative to the run, so the ACTIVITY column reads the same on any day.

Legacy root routes (/reference/cli/ and the rest) redirect permanently to their /docs/ locations through docs/vercel.json. Three validators run under make docs-check and in the CI docs job: the redirect table must equal the set derived from the nav, every nav page must have its twin and appear in llms.txt, and every local link and anchor in the hand-written pages must resolve in the built site. The assembled docs/site also may not contain build tooling, the website sources, or dotfiles.

Where to look:

  • docs/website/ is the hand-written tier: two HTML pages, their Markdown twins, a monochrome stylesheet, self-hosted Inter and JetBrains Mono under their OFL licenses, and the SVG diagrams.
  • docs/zensical-docs.sh builds the docs tier into docs/site/docs and assembles the website files at the site root.
  • docs/scripts/check_*.py are the validators; docs/vercel.json is generated from the nav and checked against it.
  • docs/index.md and docs/development/contributing.md carry the docs-tier rewrite and the two-tier explanation.

Nothing is deployed by this PR. make docs-deploy still pushes the prebuilt docs/site to the existing Vercel project, and the /docs/ move means the og.png on the website-assets branch is now served from /docs/assets/og.png.

🤖 Generated with Claude Code (claude-fable-5-1)
Co-authored-by: Claude Fable 5.1 noreply@anthropic.com

wesm and others added 4 commits September 4, 2026 21:08
kwt.sh opened straight into the Zensical documentation, so the first page a
visitor saw was a reference index rather than an explanation of what kwt is
for. The site is now three tiers: a hand-written product page at /, a
nine-stop guide at /guide/, and the Zensical documentation moved under
/docs/ and reduced to technical reference for people and their agents.

The product page and guide are static HTML under docs/website with exact
Markdown twins at /index.md and /guide.md. Every documentation page keeps its
Markdown source beside the rendered page at /docs/<page>.md and advertises it
with a rel=alternate link. /llms.txt indexes all three tiers and the build
fails if it omits a nav page, so machine readers always have a complete map.

Moving the docs under /docs/ changes every published URL. docs/vercel.json
now carries a permanent redirect for each legacy page route and Markdown
twin, generated from the Zensical nav and enforced by
check_vercel_redirects.py. check_built_site.py validates the assembled site
on every `make docs-check` run: required root files, twins, local links and
anchors, llms.txt coverage, sitemaps, and a forbidden-file inventory so build
scripts and dotfiles never ship. The Vercel deploy still uploads docs/site
prebuilt, so the redirect table is copied into that directory.

Terminal captures on the product page use the real output shapes: the
kwt-wt-<repo>-<branch>-<hash> session name, the prune reason codes such as
would_remove and pr_not_merged, and the doctor report headings. The pinned
install version moves from v0.5.0 to v0.5.1, the latest tag with release
artifacts.

Generated with Claude Code (claude-fable-5-1)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The first cut of kwt.sh had an invented logomark, a teal-on-navy palette,
a background grid and watermark in the hero, and ten sections. Wes reviewed
it and asked for the logo to go, the palette to change, the hero decoration
to go, and the page to be shorter.

The site now uses the carbon monochrome palette from katatracker.com, so
the two Kenn product sites read as one family. The wordmark is plain text,
including the favicon. The hero is the headline, the dashboard capture, and
the install commands, with no decoration behind them.

The product page keeps isolation, automation, safety, and interfaces, then
points at the guide. Dashboard keys, layouts, maintenance, multi-machine
sync, and the boundary comparison were cut from the product page; the guide
already covers each of them as a stop, so nothing is lost from the site.
The Markdown twin and llms.txt summary follow the shorter page.

Generated with Claude Code (claude-fable-5-1)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The wordmark and hero brand read "kwt.sh" with the suffix dimmed. kwt.sh is
the site address; the product is kwt, and the page should name the product.

The mono wordmark also carried negative letter-spacing, which made the
glyphs collide. Monospace faces are designed on a fixed advance, so the
wordmark and hero brand now use the face's own spacing.

Generated with Claude Code (claude-fable-5-1)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The dashboard on kwt.sh was a hand-typed HTML mock. Its columns drifted
out of alignment and it showed states the dashboard never renders, so
it misrepresented the product on the first screen a visitor sees.

The capture is now generated: docs/screenshots/generate-tui.sh builds
kwt, seeds two synthetic repositories with dirty, ahead, behind, and
live worktrees, runs the real dashboard inside a private tmux server,
and renders the pane to docs/website/assets/dashboard.svg with freeze.
Every state on screen comes from kwt itself, so the picture stays
truthful when the TUI changes; rerun make docs-screenshot after such
changes.

The fixture runs under its own KWT_HOME, TMUX_TMPDIR, and Git config so
it never registers into, or reads from, the operator's own projects and
daemon. Dates and file times are relative to the run, so the ACTIVITY
column reads the same on any day.

Generated with Claude Code (claude-fable-5-1)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@roborev-ci

roborev-ci Bot commented Sep 5, 2026

Copy link
Copy Markdown

roborev: Combined Review (20dd0a7)

Verdict: Two medium-severity issues need attention; no high or critical findings were reported.

Medium

  • docs/vercel.json:217-219 — The catch-all /assets/:path* redirect also matches new website assets, redirecting them to nonexistent /docs/assets/... paths and breaking homepage and guide visuals. Narrow the redirect to documentation assets or use a separate namespace.

  • docs/zensical-docs.sh:143find -maxdepth is unsupported by macOS/BSD find, causing the documented local docs build to fail after Zensical completes. Replace it with a portable expression or depth-independent cleanup approach.


Reviewers: 2 done | Synthesis: codex, 7s | Total: 9m33s

The redirect table sent every /assets/ request to /docs/assets/. That
matched the product page's own images at /assets/dashboard.svg and the
diagrams beside it, so on Vercel the hero and section visuals would
have redirected to paths that do not exist. The local preview never
applies redirects, which is why the breakage was invisible before
review.

Only the social preview image ever had inbound links at the legacy
asset route, so the redirect now covers /assets/og.png alone. The
built-site check also rejects any redirect whose source shadows a file
the site serves, or whose concrete destination is missing, so a future
redirect cannot break served files without failing docs-check.

Generated with Claude Code (claude-fable-5-1)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@wesm

wesm commented Sep 5, 2026

Copy link
Copy Markdown
Member Author

Review follow-up for 20dd0a7:

  • /assets/:path* redirect: confirmed and fixed in 1a872e1. The redirect now covers /assets/og.png only, and check_built_site.py rejects any redirect whose source shadows a served file or whose concrete destination is missing, so make docs-check fails on a repeat.
  • find -maxdepth on macOS: not a defect. Apple's /usr/bin/find accepts -maxdepth as a primary when it follows the path, which is how zensical-docs.sh uses it. Verified with /usr/bin/find docs/screenshots -maxdepth 1 -name '*.json' on Darwin 25.6. No change.

@roborev-ci

roborev-ci Bot commented Sep 5, 2026

Copy link
Copy Markdown

roborev: Combined Review (1a872e1)

Verdict: High-severity publication-path vulnerabilities can expose local credentials or other sensitive files during documentation deployment.

High

  • Arbitrary file publication via navigation paths and symlinksdocs/scripts/copy_public_markdown_sources.py:44-50
    Nav-listed paths can reference symlinks targeting local secrets or files such as /proc/self/environ; shutil.copyfile follows them and copies their contents into the published site. Constrain source paths beneath docs_dir, reject symlink components, require regular files, and constrain destinations beneath site_dir.

  • Deployment bypasses site-inventory checksdocs/zensical-docs.sh:74-102,121-144, Makefile:160-162
    docs-deploy runs only docs-build, allowing sensitive files such as credentials.json, token.json, or .pem files to reach the deployment output without validation. Make deployment depend on docs-check and/or reject forbidden files during site assembly.


Reviewers: 2 done | Synthesis: codex, 10s | Total: 16m57s

docs-deploy built the site and shipped it without running the checks
that CI runs on pull requests. A maintainer deploying from a local
checkout could publish broken links, a stale redirect table, or a file
the inventory check forbids, because nothing between build and upload
looked at the output.

docs-deploy now depends on docs-check, so the exact docs/site tree that
goes to Vercel has passed the link, twin, redirect, and inventory checks
first. The checks take a few seconds, which is cheap next to a bad
publish.

Generated with Claude Code (claude-fable-5-1)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@wesm

wesm commented Sep 5, 2026

Copy link
Copy Markdown
Member Author

Review follow-up for 1a872e1:

  • Deploy bypasses the inventory check: accepted and fixed in 379ad34. docs-deploy now depends on docs-check, so the docs/site tree that goes to Vercel has passed the link, twin, redirect, and forbidden-file checks first.
  • Arbitrary file publication via nav paths and symlinks: not a vulnerability boundary, no change. The nav is docs/zensical.toml, a committed file, and the copier runs on the temporary docs copy the build script makes. Anyone who can land a hostile nav entry or a symlink in the repository can edit the build script in the same commit, so path containment in the twin copier would not protect anything the repository's own review does not already cover.

@roborev-ci

roborev-ci Bot commented Sep 5, 2026

Copy link
Copy Markdown

roborev: Combined Review (379ad34)

Verdict: Two medium-severity issues require attention; no critical or high-severity findings were identified.

Medium

  • docs/scripts/check_built_site.py:146-151docs-check validates local links only in three handwritten HTML pages, not the rendered /docs/ pages. Broken links or fragments in generated documentation can therefore be deployed. Update validation to traverse all generated HTML pages.

  • Makefile:155-162zensical-docs.sh supports KWT_DOCS_SITE_DIR, but docs-check, docs-preview, and docs-deploy hardcode docs/site. With the override set, checks may inspect stale output and deployment may publish a different directory. Use the configured site directory consistently or reject the override for these targets.


Reviewers: 2 done | Synthesis: codex, 8s | Total: 16m4s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant