Skip to content

Move the landing page and docs into one Next.js site, ready for launch - #10

Merged
samkim merged 55 commits into
mainfrom
landing-page
Sep 30, 2026
Merged

samkim merged 55 commits into
mainfrom
landing-page

Conversation

@samkim

@samkim samkim commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Motivation

The docs site and the new landing page were two Vite entries under showcase/docs/app, with docs on hash routes (/docs/#/<slug>), no shared layout, and no hosting. This moves both into one Next.js app in a top-level site/, deployed on Vercel at openap.org. Docs get real paths, and the two pages share one root layout, which carries the theme and the cookieless analytics.

The landing page is also rewritten to tell the README's story, and the site is readied for a public launch.

Summary of changes

Site migration (site/)

  • Next.js 16 App Router with @next/mdx. The 131 guides live at /docs/<slug>, prerendered, and an unknown slug returns 404.
  • One root layout: next-themes for light and dark, and PostHog set to cookieless, pageviews only, production only, via i.authzed.com.
  • Pagefind search, run after next build, with Cmd+K (Ctrl+K off Apple platforms).
  • A prebuild check.ts validates the media manifest, the refs sidecars, every /docs link and anchor, and lede markup.
  • showcase/docs and its Vite config are removed.

Go and repo changes that go with it

  • clidocs and crddocs emit /docs/oap-* and /docs/crd-* links.
  • mage docs:cli writes into site/content/docs. The CLI reference is regenerated.
  • The web-bundle diff base and the auditgen default diff base are main, not master. Other master references are updated too.
  • oap channel's help text no longer calls webhooks and schedules "future".

Landing page

  • It follows the README's order:
    • the hero, with the four trust questions;
    • the credential-scope problem and the comparison table;
    • the six primitives;
    • controls in six areas;
    • Agent Builder;
    • everything else;
    • OWASP coverage;
    • defense in depth.
  • Claims are checked against the code. Among the fixes:
    • "Nothing phones home" is replaced, since SpiceDB's default telemetry stays on.
    • ASI07 is re-rated Partial.
    • Revocation is "at the next check".
    • Plan gating is opt-in.
  • Includes a shared site footer with the license and the AuthZed credit, and a proper OWASP CC BY-SA 4.0 attribution.

Docs content
Reconciled with the code and the primary message:

  • rate limits are opt-in;
  • the prompt-injection classifier ships;
  • prompt delimiters are an aid, not the boundary;
  • oap install examples pass --builder-starters;
  • only GKE provisions artifact storage;
  • the correct quickstart example path;
  • the docs entry page leads with the primary message.

Install prerequisites are listed, each linking to the tool's own install page. README's Desktop line now says it's for trying OAP and demos.

Launch readiness

  • Canonical URLs, Open Graph and Twitter tags, a generated share card, robots.txt, a sitemap, a favicon, an apple-touch-icon, and a styled 404 page.
  • The docs have a top bar and menu under 900px.
  • Accessibility:
    • Links inside running text are underlined.
    • The lightbox gets modal focus handling.
    • The landing page has a <main> landmark.
    • Search results are announced to screen readers.
  • Search failures are logged and shown to the reader.
  • Security headers, plus a production CSP.

Alternatives considered

  • Docs frameworks (Fumadocs, Nextra, Docusaurus, Starlight, hosted options): each would have meant converting the guides' ESM meta exports or fighting a theme. Plain Next.js with @next/mdx reads the metadata natively.
  • next-mdx-remote, as authzed/web uses: it is archived and can't read ESM exports.
  • Keeping hash routes with a redirect: nothing was deployed, so no external link depends on them.

Provenance

  • Author (person, or model and version): Claude Opus 5.5 (1M context), directed by Sam Kim
  • Harness or tooling, with version: Claude Code 2.1.285
  • Person who read the diff: not yet; the diff needs a human read before merge (see below)

Ship gate

  • mage test:unit
  • mage test:integration
  • mage test:e2e

Results:

mage test:unit         exit 0   554 packages ok, 0 failed   (15:45 to 15:54)
mage test:integration  exit 0   494 packages ok, 0 failed   (15:54 to 16:06)
mage test:e2e          exit 0    64 packages ok, 0 failed   (16:06 to 16:17)
  ok  test/e2e/bronzethread  635.379s
  ok  test/e2e/steelthread    25.761s

The branch is 2 commits behind main (#5, #8). Neither touches a file this branch changes, so the suites ran on the branch as-is.

Regeneration

  • Changed a +kubebuilder:rbac marker or a CRD-shaping field in pkg/apis/v1alpha1/*_types.go → ran mage gen:api and mage manifests (not applicable)
  • Edited anything under config/** → ran mage manifests (not applicable)
  • Changed a cobra command or a CRD schema → ran mage docs:cli / mage docs:crd
  • Ran mage fmt:all until mage fmt:check is clean

Coverage

  • This adds user-visible behavior, and a bronzethread bundle exercises it, or it does not add user-visible behavior. The user-visible change is the website; no platform or agent behavior changes, so no bundle applies.
  • This touches authorization, the SpiceDB schema, or the approver model, and mage test:integration + mage test:e2e are green, or it touches none of those. It touches none of them.

Before requesting review

  • The PR holds a single change. If it has several parts, they cannot land independently (explain why below).
  • A person has read every line of the diff, or the note below explains how to check the parts they did not.

The parts are coupled: the generators' new link format only resolves on the new site, the landing and docs share one layout and footer, and the launch fixes edit files the migration creates.

Reading the diff: most of the line count is the 131 guides moving from showcase/docs/guides to site/content/docs (history-preserving renames), their #/ links rewritten to /docs/, and the regenerated oap-* and crd-* reference pages. The hand-written code is site/app, site/components, site/lib, site/scripts, site/next.config.mjs, plus the Go files under pkg/gen, magefiles and cmd/oap/internal/channelcmd. The docs prose edits from the launch review are in commits af268a8 and 3b4e74f.

Before deploying (outside this repo)

  • Vercel project: root directory site, with "Include files outside the root directory" on (the brand SVGs come from docs/assets/brand). Confirm the install step can run pnpm@12.3.4.
  • Set NEXT_PUBLIC_POSTHOG_KEY for Production. Enable cookieless server hash mode in PostHog.
  • Point openap.org at the project, and confirm preview deploys send noindex.
  • Make the repository public: the GitHub, Source and license links depend on it.

🤖 Generated with Claude Code

samkim and others added 30 commits September 28, 2026 19:19
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Also update the spec's sequencing: the uncommitted Vite landing work is
the port source and is deleted once site/ serves both pages.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Creates site/ as a standalone Next.js 16.3.6 + Turbopack package with its
own package.json/pnpm-lock.yaml (joins no workspace), vitest wired up, and
an MDX component map. Proves the plan's one open risk: importing brand SVGs
from the repo's docs/assets/brand/ across the site root resolves correctly
under Turbopack (widened turbopack.root + outputFileTracingRoot), verified
by a production build that emits a content-hashed oap-wordmark-light SVG.

pnpm add hit ERR_PNPM_IGNORED_BUILDS for core-js and esbuild (not sharp, as
the brief anticipated, but the same pnpm build-approval gate); added
site/pnpm-workspace.yaml with allowBuilds for sharp/esbuild/core-js to
unblock install, following the same key showcase/pnpm-workspace.yaml uses.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Relocates the 129 MDX guides, refs sidecars, manifest, and media from
showcase/docs into site/content and site/public so the new Next.js
site owns its content directly. Points the checker (now `pnpm check`
in site/) and the Go docs generators (magefiles/clidocs.go) at the new
location.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Ports the docs chrome from the Vite app in showcase/docs/app into site/:
root layout wired to next-themes (data-theme attribute, dark/light/system,
icons, viewport theme-color), the sidebar/nav/article components
(Wordmark, NavLink, ThemeToggle, media, Callout, Coverage), the docs.css
chrome scoped to .doc-app rather than the whole document, and the
/docs and /docs/[slug] routes with generateStaticParams over all 129
guides. Adds linkKind() to classify MDX anchors as docs/external/plain
and wires it into mdx-components.tsx.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Copies Landing.tsx, landing.css and OapMark.tsx from the Vite showcase
app into site/app/(landing)/, rewrites the hash-route docs links to
real /docs/<slug> paths, extracts the OWASP coverage table into
owasp.ts, and pins its templated anchor hrefs with owasp.test.ts
against content/docs/owasp-top10.mdx.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Adds a loader/URL helper (site/lib/pagefind.ts) that dynamically imports
the Pagefind bundle written to public/_pagefind by `pnpm build`, guarded
against Turbopack/webpack resolution via inline ignore comments since the
bundle doesn't exist at compile time. Mounts a client Search component in
the docs sidebar, right after the brand row, that falls back to a "search
is available after pnpm build" note under `next dev`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
posthogOptions is a pure options function: it initializes only when a key
is set and NEXT_PUBLIC_VERCEL_ENV is "production", with cookieless_mode,
person_profiles: never, and every replay/heatmap/survey/flag capture
disabled. Analytics.tsx calls it once from the root layout.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
They were previously inert only as a side effect of advanced_disable_flags
and disable_external_dependency_loading; pin them directly so a future SDK
change can't silently re-enable a chat/tour widget.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
The Next.js site/ app now serves both the landing page and the docs
(Tasks 4-8), so the old Vite docs app in showcase/docs/ is no longer
needed. Deletes it along with vite.docs.config.ts, drops the docs-only
scripts and dependencies from showcase/package.json, adds site/**
to the repo formatter, writes site/README.md and site/AGENTS.md, and
updates every doc that still pointed at the old showcase/docs layout.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
oxfmt couldn't converge on two inline-code spans that escaped backticks
inside a single-backtick span (`import(\`...\`)`), which made it mangle
surrounding prose on reformat. Rewrote them as double-backtick spans, and
moved the spec's Date/Status onto separate bullet lines so they survive
reflow, then ran oxfmt so both files are clean under mage fmt:check.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Each guide wrote its lede as a multi-line <p className="doc-lede"> block.
MDX treats the lines inside a block-level JSX element as flow content and
wraps them in their own paragraph, so the prerendered HTML was
<p class="doc-lede"><p>...</p></p>. The browser's parser closes the outer
<p> when the inner one opens, so the served DOM no longer matched the tree
React hydrates against, and every docs page with a lede threw React error
#418 in the production build. A <div> may hold a <p>, so the lede now
parses exactly as rendered.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Next 16's dev server refuses its dev resources to any origin but
localhost. Opened at http://127.0.0.1:5179, the HMR websocket was refused
(403, "Blocked cross-origin request to Next.js dev resource /_next/hmr")
and the page never hydrated: the search input carried no React props, so
its onFocus/onChange never ran, loadPagefind was never called, and neither
the unavailable note nor a /_pagefind/pagefind.js request appeared. The
same page at localhost hydrated and searched normally. Search itself was
never at fault.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
MDX wraps a top-level lede paragraph in its own <p>; a <p> nested inside
that <p> is invalid HTML, the browser re-parents it, and React throws
hydration error #418 in production only. site/lib/lede.ts adds a pure
checkLedeTags function (TDD: RED with the test importing a module that
didn't exist yet, GREEN after implementing it), wired into
scripts/check.ts so pnpm check fails the build if a guide regresses to
<p className="doc-lede">. site/AGENTS.md's authoring recipe now states
the rule and the reason.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
package.json pins packageManager to pnpm@12.3.4, matching the pnpm that
wrote the lockfile; the lockfile gains the packageManagerDependencies
block pnpm records for that pin. pnpm-workspace.yaml denies core-js's
build script explicitly (its postinstall is only a donation banner) —
pnpm treats an absent entry as pending approval and hard-fails
`--frozen-lockfile` install, so `false` is what "don't grant it" has to
be, not just removing the line. Verified with
`pnpm install --frozen-lockfile` (exit 0).

site/README.md's Deploying section lists the remaining one-time owner
actions: NEXT_PUBLIC_POSTHOG_KEY scoped to Production only, PostHog's
Cookieless server hash mode, keeping Vercel's System Environment
Variables exposed (the gate reads NEXT_PUBLIC_VERCEL_ENV), enabling
Corepack so the pinned pnpm is used, and confirming
/_pagefind/pagefind.js returns 200 after the first preview deploy.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
…ration

Prose and comments still described the retired Vite showcase docs app or
its docs/public output path. Fix wording only, no behavior change:

- "showcase docs'" -> "the site" in magefiles/magefile.go (Docs
  namespace doc), pkg/gen/clidocs/clidocs.go, pkg/gen/crddocs/crddocs.go,
  cmd/oap/clidocs_gen_test.go.
- site/lib/manifest.ts: the manifest path is site/content/_manifest.json,
  hand-maintained, not "docs/_manifest.json ... the media pipeline
  writes."
- showcase/.gitignore and showcase/engine/capture/clip.mjs: published
  media lives under site/public, copied there by hand, not docs/public.
- site/app/(landing)/landing.css: the token-copy rationale is that site/
  is its own package outside the web/ workspace, not that showcase/ is.
- site/app/docs/docs.css: the theme attribute is stamped by next-themes
  before paint, not a hand-rolled "pre-paint script".
- site/README.md / site/AGENTS.md gotcha: dev has no search index at all
  on a clean checkout; after any pnpm build, dev serves that (possibly
  stale) index like any other static file, rather than never having
  search. (site/AGENTS.md's half of this landed in the lede-rule commit,
  since git add swept the whole file.)

Also moves docs/assets/brand/README.md's site/app/(landing)/OapMark.tsx
entry from the "reference the files here directly" prose into the
"Copies of the geometry" table it belongs in — OapMark inlines the
logomark's geometry rather than loading the SVG file.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Search lives in the docs layout, which persists across route changes.
Picking a result routed to a new page without clearing the query input
or result list, so the persistent layout kept showing them over content
the visitor didn't search for. A usePathname effect now clears the
input (via a ref, since it's uncontrolled) and resets state to idle on
every pathname change, bumping the generation counter first so a search
already in flight can't repopulate state after the clear.

Screenshot and ScreenshotSeries images are role="button" with
tabIndex={0} (a real <button> can't hold an <img> the way the lightbox
layouts need) but had no keyboard handler, so they were focusable but
not operable from a keyboard. A shared activateOnKey helper responds to
Enter and Space the way a native button would, calling preventDefault
on Space so the page doesn't scroll.

No new test infra: this repo's vitest setup only covers plain-function
node-environment tests (vitest.config.ts: environment "node", include
**/*.ts, no @testing-library/react or jsdom) and has no existing
component-test pattern to extend; verified instead via typecheck, the
full site test suite, and a production build.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
test:unit's stale-web-bundle check defaulted to master, which this repo
doesn't have, so it logged a diff failure and skipped on every run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Picks up the oap directory and oap preferences families, the
OAP_DESKTOP_SSH_KEY rename, and the new oap tools gen behavior.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
The repo's base branch is main. Update the audit generator's default
diff base (and AUDIT_DIFF_BASE docs), the ship-gate and audit prose in
AGENTS.md, the OWASP coverage page's assessment scope, and branch
mentions in comments. Upstream skill refs pinned to a third-party
repo's master branch and "master Secret" (a credential term) are
unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Each platform binds only its own modifier: on macOS Ctrl+K is the
text-field kill-to-end-of-line binding, and Super+K belongs to the OS
elsewhere. The search box shows the platform's hint once mounted (so
server HTML never mismatches), declares aria-keyshortcuts, and Escape
clears and blurs it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Lead with "a secure way to run enterprise AI agents" and follow the
README's order: the credential-scope problem and its comparison table,
the six primitives, the twenty-seven controls in six areas, Agent
Builder, a compact "everything else" strip, then the OWASP map with the
test evidence folded into it. Close on defense in depth.

The hero terminal now offers the README's two local paths (Desktop and
kind) instead of an install into an existing cluster. Drop the
whitepapers section and its placeholder links, the seam grid, and the
drifting internal counts. The "no telemetry" claim is narrowed to the
runtime, since the site itself now carries cookieless analytics. The
footer credits AuthZed, using SpiceDB.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Cut every section's prose to short sentences and raise body text size
and spacing, so the page scans rather than reads as a wall. Remove the
hero and primitive-card chips, which repeated the text beside them; the
OWASP coverage pills and the Draft marker stay because they carry
status. Retitle the OWASP section "Coverage of the OWASP Agentic Top
10" and state the self-assessment plainly.

The theme toggle moves from the nav to the footer, which also lets the
wordmark stay visible in the nav at phone width.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Split the landing footer into two rows: the mark and links on top, and
a bottom bar with "Built by AuthZed, using SpiceDB" on the left and the
theme toggle on the right. Raise the landing page's sans-serif text one
pixel throughout; the monospace labels keep their 12px ceiling.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
The oversized "01"–"06" behind each section numbered chapters that no
longer form a sequence, and competed with the numbering that does carry
meaning (the four hero questions, the six primitives). Each section is
still marked by its kicker and the rule above it. The section clipping
that existed only to contain the numerals goes with them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Chromium can report navigator.userAgentData.platform as "" (some privacy
configurations, and after device emulation). The `??` fallback kept the
empty string, so a Mac was treated as non-Apple: the hint read "Ctrl K"
and Cmd+K did nothing. platformName now lets an empty hint fall through,
with table tests for each case.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
samkim and others added 24 commits September 29, 2026 11:58
- SiteFooter (components/) replaces the landing-only footer and now sits
  under every docs guide too: links on top, the AuthZed credit bottom
  left, the theme toggle bottom right. It styles itself from --sf-*
  variables that .lp and .doc-app map, the same pattern as the toggle.
  The docs sidebar no longer carries a toggle.
- The nav shows the logomark alone; the hero shows the full wordmark,
  sized by width (400px, capped at the column). The wordmark's per-theme
  ink swap moves out of docs.css into components/wordmark.css so the
  landing page gets it too.
- Plainer claims: "The AI never decides what it's allowed to do. OAP
  checks every action before it runs." Building from source is framed as
  every image coming from code you can review.
- Larger small text: monospace eyebrows, labels, captions and notes move
  up half a pixel to a pixel. Card eyebrows had been rendering at body
  size because `.lp-prim p` and `.lp-slab p` outranked them.
- On phones, the OWASP table now hides the Known gap header along with
  its column, and its caption wraps instead of clipping.
- OapMark moves to components/ (brand README updated).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
The area titles (18px/500) read almost the same as each bullet's bold
lead-in (15.5px/500). They are now 22px with tighter tracking and a rule
beneath, so each card reads heading first, then list. Card padding grows
to match on desktop and tightens on phones.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
From an LLM-writing check of the rendered page: drop the "almost always"
hedge from the problem heading, and rewrite four of the page's eight
"X, not Y" reversals (the credential valet-key line, "not just what its
task needs", "never the secret itself", "denied, never guessed"). The
reversals that carry the point stay, as does the security intro.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
"Desktop · macOS" and "Kubernetes · kind" read as four options split by
dots. The tabs are now "macOS desktop" and "Local Kubernetes", the
README's own names, set in their natural case so "macOS" survives.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
- Under the four trust questions, one line now closes the loop: "OAP
  answers each one in the platform, before the agent acts. See how →",
  linking to the comparison table (#compare), which answers them row by
  row.
- The problem heading states the consequence rather than a mismatch:
  "Your agent can reach everything its credentials can."

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
- The hero's single button is now "How it stays secure" (primary); the
  "Get started" button there is gone, since the nav already carries it.
  The line under the four questions stays, without its link.
- The hero wordmark competed with the headline, so it goes; the nav
  logomark grows from 20px to 28px to carry the brand.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
The nav now shows the wordmark (logomark plus "Open Agent Primitives")
at 38px tall in place of the bare logomark, so the one logo on the page
names the project. The brand set has only the stacked two-line
wordmark; a single-line lockup would be a new asset.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
"Six concerns every agent has to solve." broke as "…has to / solve."
Section headings, the hero title and card titles now use
text-wrap: balance, so lines come out even. Two phrases balancing would
split badly are held together: "Twenty-seven controls," and the OWASP
heading's "Top 10." with its Draft marker.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
The anatomy-of-a-check panel and its recorded-trace companion came
after the comparison table had already made the point, gave no scenario
for the denial, and showed a trace unrelated to the example. The section
now ends on the table. Their styles go with them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
"Every agent is built from them" read as if each agent must use all six.
The primitives lede now says any agent can be built from them, using
only the ones it needs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
The primitives lede now runs definition first, then offering: "A
primitive is a basic building block that agents rely on, whatever they
do. OAP ships a working implementation of every one."

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
"The platform enforces every control. No prompt or tool output can
affect enforcement." replaces the passive "enforced by the platform,
not requested of the model" phrasing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
The "Everything else" channels card named five surfaces. It now adds
scheduled runs (bento) and sub-agent conversations (the agent kind),
and says transports are pluggable. "Sub-agent conversations" rather
than "agent-to-agent" keeps it consistent with the OWASP ASI07 row.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
Both used a placeholder; they now link to
https://github.com/authzed/openagentprimitives.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
- The footer's Community link (landing and every docs page) now goes to
  the AuthZed Discord, https://discord.gg/TUd4k5McMX, where
  authzed.com/discord redirects.
- The OWASP section's "Full assessment" button is gone; "Read the
  coverage map" remains. No example.invalid URLs are left in the site.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LdnJCJHVx2mfpfoHi6pbqG
- "Nothing phones home" was untrue (SpiceDB's default telemetry is left
  on), so that card becomes "Under your control": OAP runs inside a
  cluster your team operates.
- The Channels card drops "sub-agent conversations"; the landing page is
  about channels, and the phrase contradicted the ASI07 row.
- The ASI01 gap no longer mentions meta tools, which read as actions
  skipping authorization.
- The footer says OAP is open source under Apache 2.0, linking LICENSE.
- The OWASP credit now names the work, its author and its license with
  links, on the landing page and at the foot of the OWASP docs page.
- The quickstart installs from examples/pm-agent, the path that exists.
- README: Desktop is for trying OAP and demos, not production; the docs
  link to openap.org/docs, with local instructions kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- metadataBase is https://openap.org (lib/site.ts), so canonical and
  Open Graph URLs resolve to the production site on every deploy.
- Every page has a canonical link, og:url, and the same current
  description; docs pages get article-type Open Graph tags.
- A build-time 1200x630 share card (app/opengraph-image.tsx), attached
  explicitly to pages that set their own openGraph, since that replaces
  the inherited image.
- robots.txt and sitemap.xml (the landing page plus all 131 guides).
- favicon.ico and a 180px apple-touch-icon, drawn from the brand icon on
  a dark tile; the SVG favicons stay for browsers that use them.
- A styled 404 page with links back to the docs and home, and one title.
- /docs now redirects with 308 rather than 307.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each change was confirmed against the code and approved item by item:
- Drop the hero note that every image comes from reviewable code; the
  install also pulls third-party images.
- "Built in and swappable" names the README's list (runner,
  authorization, approvals, sandboxing, credentials, memory, audit)
  rather than "every core component".
- "Instant revocation" becomes "the next action is refused".
- "Twenty-seven controls, in six areas" becomes "Controls in six areas",
  since the cards show a selection.
- The comparison row's OAP answer to an injected instruction is "Cannot
  widen what it's authorized to do", which holds by default; plan gating
  is opt-in. README's table matches.
- "Nothing is enabled until someone adds it" is scoped to tools and
  capabilities, since breakers and network policy are on by default.
- The OWASP heading loses its Draft badge.
- ASI05 describes per-session isolation instead of "deferred" work, and
  ASI07 is re-rated Partial: delegation is typed, authorized and bounded,
  and stays within one cluster.
- The OWASP caption is counted from the rows (coverageSummary, tested),
  so a re-rating can't leave it stale.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Approved item by item, each checked against the code:
- Rate limits and data-volume budgets are opt-in; only circuit breakers
  are on by default (safe-tools, OWASP ASI02).
- The prompt-injection classifier ships; the OWASP page and the coverage
  HTML no longer say it doesn't.
- Prompt delimiters are described as an aid to the model, not the
  boundary; the boundary is that tool output cannot reach a privileged
  action without the platform's checks (agent-loop, agent-definition,
  OWASP ASI01).
- `oap install` examples pass --builder-starters, with a note that it or
  --without-builder is required.
- Only GKE provisions artifact storage; EKS and AKS take
  --artifact-store-url.
- The docs entry page leads with the primary message and defines a
  primitive.
- One rule for who checks run against: the user an agent acts for, or a
  userless session's own principal (the session or a declared service)
  with no standing grants.
- Sandboxes get micro-VM isolation when their class sets a runtime class,
  not by default.
- install-desktop carries the build commands; ASI05/ASI06 gaps are stated
  plainly; the OWASP primitive names and Authorization link are fixed.
- ASI07 is re-rated Partial on the docs page, in channels, and in the
  coverage HTML.
- `oap channel` help no longer calls webhooks and schedules "future";
  the CLI reference is regenerated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Under 900px the sidebar used to be hidden entirely, taking the guide
list, search and home link with it. It now becomes a sticky top bar with
the wordmark, the search field and a Menu button; Menu opens the guide
list as an overlay beneath the bar. The menu closes on navigation and on
Escape (returning focus to the button), and search results drop down
across the full width. DocNav holds only the open state, so the page
still has a single search box. Desktop is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Links inside running text are underlined: docs articles, the footer
  credit and landing notes. Their colour alone was only ~2.4-2.8:1
  against the text around them, under the 3:1 a colour-only link needs
  (WCAG 1.4.1). Text contrast itself already passed AA in both themes.
- The image lightbox behaves as the modal it declares: focus moves to
  its close button, Tab can't leave it, focus returns to the thumbnail on
  close, and it is named by its caption.
- The landing page's content sits in a <main> landmark.
- The landing phone nav keeps "Docs" beside "Get started", with the
  wordmark and spacing trimmed so both fit inside the side padding.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- A failed index load is logged instead of swallowed, and on a deployed
  site the message reads "Search is unavailable right now." rather than
  the dev-only `pnpm build` hint.
- A query that throws is caught, logged with the query, and shown as
  "Search failed. Try again." instead of an unhandled rejection.
- A visually hidden status line announces the result count, "No
  matches.", or the failure to screen readers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
HSTS, nosniff, X-Frame-Options DENY, a strict Referrer-Policy and a
Permissions-Policy that denies camera, microphone and geolocation. In
production a Content-Security-Policy limits everything to the site's own
origin, plus i.authzed.com for analytics. Scripts need 'unsafe-inline'
because the site is static, so there are no per-request nonces, and
Pagefind needs 'wasm-unsafe-eval'. frame-ancestors is 'none'. Verified
with no violations across the landing page, docs, search, the lightbox
and video. It is left off in dev, which relies on eval.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The install overview lists Git, Go 1.26+, Mage, Docker with buildx and a
Kubernetes cluster (e.g. kind), each linked to its official install page,
then shows the clone and `mage build:oap` step. Desktop lists its extra
requirements (Apple Silicon, Xcode Command Line Tools, Docker/buildx,
curl, zstd), taken from magefiles/desktop.go, and install-init points to
the common list.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@samkim
samkim requested a review from josephschorr September 29, 2026 23:21
The migration's design spec and implementation plan were working notes
for building this branch, not project documentation. They are removed
from the repository (kept locally) and docs/superpowers/ is ignored.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@josephschorr josephschorr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@samkim
samkim merged commit 3436c3a into main Sep 30, 2026
5 checks passed
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