Skip to content

Redesign the landing page to match the new mockup - #31

Merged
samkim merged 5 commits into
mainfrom
landing-page-redesign
Oct 19, 2026
Merged

samkim merged 5 commits into
mainfrom
landing-page-redesign

Conversation

@samkim

@samkim samkim commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Motivation

The landing page is moving to a new design, delivered as a static mockup (oap-landing.html). This PR ports that mockup onto the live Next.js page as designed. Copy and diagrams are carried over faithfully, including claims that a code fact-check found inaccurate. Those findings are posted as review comments on this PR, so the port and the corrections can be reviewed separately.

Summary of changes

  • Layout: a four-questions band below the hero, linking into the page (#problem, #area-1/2/6). The problem section now has text beside a diagram. The primitives are a list beside a card deck that deals as you scroll. Security areas are tabs addressable by URL hash (#area-N), and every panel renders without JS. Agent Builder shows numbered steps beside the clip. "Everything else" is an icon grid. The closing section has a defense-in-depth diagram.
  • Nav: an animated mark over the wordmark, and a theme menu that shares next-themes state with the footer toggle.
  • Diagrams: site/app/(landing)/geo/figures.js ports the design study's geometric figures unchanged, with a header noting they're hand-authored illustrations. GeoFigure.tsx is the typed boundary: it server-renders the SVG, and animates only visible, unpaused figures on one shared timer, honoring prefers-reduced-motion.
  • OWASP table: partial coverage is now labeled "In progress", and the gap column is now "Not yet". Gap wording is revised, and the caption has a per-row coverage bar. Labels move into owasp.ts. content/docs/owasp-top10.mdx is unchanged.
  • OapMark.tsx and ThemeToggle.tsx export their paths and icons for reuse.

Alternatives considered

  • Rewriting the figure geometry in TypeScript: rejected. It's about 650 lines of geometry with no type benefit, and keeping it identical to the design study keeps future design iterations diffable.
  • Correcting diagram content in this PR: deferred to follow-up commits, so reviewers see the as-designed port first. See the review comments.

Provenance

  • Author (person, or model and version): Claude Opus 5.5 (1M context), directed by @samkim
  • Harness or tooling, with version: Claude Code; implementation split across subagents
  • Person who read the diff: @josephschorr

Ship gate

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

Results: not run. The change is confined to site/, which is outside the Go suites. Site gate from site/:

pnpm lint       → exit 0
pnpm typecheck  → exit 0
pnpm test       → Tests 98 passed (98)
pnpm build      → check OK — 136 guide(s), 3 refs sidecar(s), 63 media entr(ies); Compiled successfully; Indexed 136 pages
mage fmt:check  → All matched files use the correct format.

Visual check: the production build was compared against the mockup in Chrome. At 1440px dark, every section's height matched exactly. At 390px light, all sections matched except the questions band, which is 16px taller: the mockup alternates 12px/16px padding there because of a CSS specificity accident, and this PR normalizes it. Other checks: no horizontal scroll at 390px, no console or hydration errors, /#area-2 selects tab 2, and the deck's card depths match the mockup mid-scroll.

Regeneration

  • Changed a +kubebuilder:rbac marker or a CRD-shaping field → n/a
  • Edited anything under config/** → n/a
  • Changed a cobra command or a CRD schema → n/a
  • Ran mage fmt:all until mage fmt:check is clean

Coverage

  • It does not add user-visible product behavior (marketing site only)
  • It touches none of authorization, the SpiceDB schema, or the approver model

Before requesting review

  • The PR holds a single change.
  • A person has read every line of the diff. Note: figures.js is a verbatim port of the mockup's script. Diff it against the mockup to check it rather than reading the geometry.

🤖 Generated with Claude Code

samkim and others added 2 commits October 13, 2026 22:18
Rebuild the landing page around the new design: a four-questions band
that links into the page, a problem split with a figure, the primitives
as a list beside a scroll-dealt card deck, the security areas as
hash-addressable tabs, numbered Agent Builder steps, an icon grid, and
a defense-in-depth figure at the close. The nav gains an animated mark
and a theme menu that shares next-themes state with the footer toggle.

The concept figures are hand-authored illustrations ported from the
design study into geo/figures.js, behind a typed GeoFigure boundary that
server-renders the SVG and animates only visible, unpaused figures on
one shared timer, honoring prefers-reduced-motion.

The OWASP table adopts the mockup's wording: "In progress" for partial
coverage, a "Not yet" column, reworded gaps, and a per-row coverage bar.
The coverage labels now live in owasp.ts beside the rows they describe.

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

vercel Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
openagentprimitives Ignored Ignored Preview Oct 19, 2026 4:46pm UTC

Request Review

@samkim samkim left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Diagram and copy accuracy review

I fact-checked the 8 diagrams this PR renders against the code. The 6 other figures in figures.js (peraction, injection, leakage, delegation, revoke, pods) aren't rendered, and I didn't review them. This PR ports the mockup as designed; these comments track the corrections for follow-up commits. Each finding cites code evidence, and I re-checked the high-severity ones by hand.

Inaccurate (fix before launch)

  • Defense-in-depth: the layer order is wrong, slot isn't a separate layer, plan and slot are opt-in, and the sandbox does hold the credential (figures.js:615, Landing.tsx:1437; the same phrase is in README.md:371 and docs/security-model.md:627)
  • Broker: MCP credentials are resolved and held by the runner, and sidecar credentials are frozen at pod creation; "handle" is the wrong term (figures.js:243, Landing.tsx:163/168; doc drift in giving-credentials.mdx:46)
  • Lens: service: is relation-less and can never be granted anything (figures.js:289)

Misleading

  • Lens: class ∩ user:maya. The class is a ceiling, not an intersected subject.
  • Gate: gh api shown as allowed without its GET-only constraint
  • Define: "in git" and "own … memory"
  • Channels: cron isn't a channel kind (bento is)
  • Memory: company:acme isn't a shipped type, and sessions aren't limited to one slot
  • Union: the figure and the copy beside it describe different problems (minor)

Pre-existing card copy (unchanged in this diff, so it can't take inline comments)

  • Landing.tsx:143, "kept in git": same issue as the define figure.
  • Landing.tsx:153, "never through a shell": technically false. Credentialed calls go through a fixed sh -c loader (pkg/tools/exec/remote/env.go:136-140, :291). The model's args arrive as positional "$@" and are never interpolated, so the property holds. Suggested: "argv only, never shell interpolation".
  • Landing.tsx:163, "the agent never holds them": see the broker comments.

Verified accurate: denied calls never reach the tool (loop_dispatch.go:755-756); each session gets its own pods and they're reaped when done (agentsession/controller.go:3921-3946); GitHub and Slack each start a session; reading memory is a SpiceDB check; and the six gate tool names match reviewbot's toolspecs.

🤖 Generated with Claude Code

Comment thread site/app/(landing)/geo/figures.js Outdated
holds (the accent). Each cycle one more layer fails, so every layer gets to
be the one that holds. */
{
const names = ["plan", "slot", "tool spec", "call check", "sandbox"];

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Inaccurate] Defense-in-depth figure: layer order and two layers don't match the code

  1. Order. The pre-call order is fixed in pkg/authz/hooks/order.go:12-58: McpTrust (10) → Revocation (12) → ToolGuard (15) → ContentGuard (18) → PlanGate (19) → ToolCallAuthz (20) → Scope (30) → Execute. For a CLI or sandbox tool, the tool spec is validated after that, in the ToolCall controller (pkg/controllers/toolcall/controller.go:230), and then the command runs in the sandbox (:441). The real path is plan → call check → tool spec → sandbox.
  2. The slot isn't a separate layer. It's a precondition on the same SpiceDB check as the call check (pkg/agent/runner/pipeline_wiring.go:433-437, :460-464).
  3. Plan gating and slots are opt-in. Plan gating defaults to disabled (pkg/apis/v1alpha1/agentclass_types.go:1486, hooks_dataplane.go:51-54). Slots is omitempty (agentclass_types.go:1370-1373). The figure draws both as always present.
  4. The bottom layer's credential claim is false. See the comment on the closing copy.

Suggested fix: draw four layers, plan (opt-in) → call check (slot-bound) → tool spec → sandbox, with plan dashed. Alternatively, keep five and relabel "slot" + "call check" as one "call check · slot" layer. Update the aria label in Landing.tsx to match.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 938c9e5. The figure is conceptual, so it keeps five layers as representative guards, reordered to plan → slot → call check → tool spec → sandbox. The aria label now matches.

Comment thread site/app/(landing)/Landing.tsx Outdated
<p className="lp-lede">
To misuse an agent, an attacker has to get past an approved plan,
a locked slot, a tool spec, a check on every call, and a sandbox
that never held the credential.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Inaccurate] "a sandbox that never held the credential"

For CLI and sandbox tools, the broker resolves the credential into env vars, and the controller runs the command inside that tool's sandbox with them:

  • pkg/controllers/toolcall/controller.go:272-279: res, berr := r.Broker.Resolve(...) … agentEnv = res.EnvVars
  • controller.go:433-441: Env: execEnv(agentEnv, ...) → executor.Exec(...)

What is true: the credential shows up only at exec time, only for that call, after a per-exec use_token re-check (controller.go:350-360), and in that tool's own sandbox. The model never sees it.

Suggested: "…a check on every call, and a sandbox that holds only that tool's credential, only for that call."

The same wrong phrase is in README.md:371 and docs/security-model.md:627.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 938c9e5. The closing copy is now framed around the model: "…a locked slot, a check on every call, a tool spec, and a sandbox. The model never sees a credential." The same sentence is fixed in README.md and docs/security-model.md.

Comment thread site/app/(landing)/geo/figures.js Outdated
b += agent(ag[0], ag[1], 22) + `<circle class="dot" cx="${ag[0] + 30}" cy="${ag[1] + 30}" r="5"/>`;
b += `<rect data-k="tool" class="dot" x="${tl[0] - 10}" y="${tl[1] - 10}" width="20" height="20"/>`;
b += `<circle data-k="call" class="pf" r="4" cx="-10" cy="-10"/><circle data-k="kd" class="af" r="5" cx="-10" cy="-10"/>`;
b += T(ag[0], ag[1] - 34, "agent", "", "middle") + T(ag[0] + 40, ag[1] + 34, "handle") + T(tl[0], tl[1] - 22, "tool", "", "middle");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Inaccurate] Broker figure: "handle", and "straight to the tool" only holds for sandbox tools

There are three credential paths, and only one matches the picture:

  • Sandbox/CLI tools: resolved per call by the ToolCall controller and injected into the exec (pkg/controllers/toolcall/controller.go:272). The runner only stamps descriptors (controller.go:249-250). ✅ Matches the figure.
  • MCP servers: the runner resolves the credential once at session start (internal/cmd/runner/main.go:1060), freezes it on the tool (mt.SetAuth(header, value), :1220), and sends it on each MCP request. It re-resolves only on a 401 or revocation (:1267).
  • SidecarToolbox: resolved by the AgentSession controller into a per-session Secret, frozen at pod creation, with no per-use re-check (pkg/controllers/agentsession/controller.go:3538-3549).

Also, "handle" means something else in this codebase: pkg/agent/secretout returns handles for secrets a tool produces (secretout.go:1-4). For credentials going into a tool, the runner holds descriptors/references and the model holds nothing.

Suggested: relabel "handle" as "reference" (or drop it). Make "agent" "model", or make the claim explicit: "the model never sees the credential".

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 938c9e5. "handle" becomes "reference", and the claim is about the model rather than the agent.

Comment thread site/app/(landing)/Landing.tsx Outdated
hue: 2,
geo: "broker",
figLabel:
"The broker hands the credential straight to the tool at the moment of use; the agent holds only a handle",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Inaccurate] Broker aria label, plus the card body three lines up (L163)

"The broker hands the credential straight to the tool at the moment of use; the agent holds only a handle." The card body says: "Credentials resolve at the moment of use, and the agent never holds them."

Both are strictly true only for sandbox tools. For MCP, the runner process resolves the credential at session start and holds the value (internal/cmd/runner/main.go:1060, :1220). See the comment on figures.js:243.

Suggested body: "Credentials are resolved by a broker outside the model and injected into the tool that needs them; the model never sees them."
Suggested label: "The broker injects the credential into the tool that uses it; the model holds only a reference."

Related doc drift: site/content/docs/giving-credentials.mdx:46 says "The runner process never sees a credential's bytes", which is false for MCP.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 938c9e5. Card body: "Credentials are resolved by a broker outside the model and injected into the tool that needs them; the model never sees them." Label: "The broker injects the credential into the tool that uses it; the model holds only a reference." giving-credentials.mdx now says the model never sees the bytes and notes when MCP servers and sidecars get them.

Comment thread site/app/(landing)/geo/figures.js Outdated
const alone = clamp((d - 160) / 30);
q(r, "af").setAttribute("opacity", alone);
q(r, "ag").style.stroke = alone > 0.2 ? ACC : "";
setText(q(r, "subj"), d < 158 ? "class ∩ user:maya" : "class ∩ service:nightly");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Inaccurate] Lens figure: class ∩ service:nightly

service is a deliberately relation-less type, and no tuple ever names one. pkg/authz/spicedb/schema/schema.zed:84-94: "It is DELIBERATELY relation-less … It exists so that a check against a service subject RESOLVES — returning no permission". loop_subjects.go:100-103 says the same: a service subject "could be REFUSED precisely and never ALLOWED anything".

So there's no service permission set to intersect with the class. An unattended run's authority comes from slot grants on the session (check_tool_call.go:433-439, slot fillFrom: trigger), and by default the session acts as itself (agentsession:<ns>/<name>). service: is the override (schema.zed:74-82, loop_subjects.go:88-90).

Suggested: for the unattended state, show agentsession:nightly with authority from the class's slot grants. Or keep service:nightly with a caption like "no standing of its own; only the session's slot grants". Update the aria label in Landing.tsx (L177-178), which says "as the service subject its channel declares".

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 938c9e5. service:nightly is gone. The figure is now conceptual: unattended, the whole agent circle lights ("agent · full scope"), and a present user narrows it to the overlap. The aria label is updated to match.

Comment thread site/app/(landing)/geo/figures.js Outdated
X on the way out. */
{
const DENY = "var(--deny)";
const calls = [["git clone", 1], ["gh pr view", 1], ["git push", 0], ["gh pr checks", 1], ["gh pr comment", 0], ["gh api", 1]];

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Misleading] Gate figure: gh api → allow, next to gh pr comment → deny

The six names match reviewbot's real toolspec allowlists (examples/reviewbot/manifests/toolspecs.yaml:67, :104). But gh api is only allowed there under a strict CEL constraint: GET only, no method/field/input flags, and an endpoint regex limited to check-run and PR read endpoints (toolspecs.yaml:151). The same file warns that unconstrained gh api "will POST anything the token permits" (:106-108). As drawn, "gh api: allow" undercuts "gh pr comment: deny", because gh api can post comments.

Suggested: ["gh api GET", 1], plus a ["gh api -X POST", 0] entry, which tells the read-only story better.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 938c9e5. The figure now shows gh api GET allowed and adds gh api -X POST denied.

Comment thread site/app/(landing)/geo/figures.js Outdated
const d = triD(x, base, sh);
b += `<path data-k="sf${k}" d="${d}" style="fill:url(#geo-g-define)" opacity="0"/><path data-k="s${k}" class="i" d="${d}"/><path class="f" d="${holeD(x, base, sh)}"/>`;
});
b += T(250, 122, "agentclass") + T(250, 140, "in git") + Tk("lbl", 200, 326, "session", "ac", "middle");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Misleading] Define figure: "in git", and "own … memory" in the footer (L158)

  • "in git": an AgentClass is a cluster CRD. Nothing reads it from git. The docs only say you can keep the YAML in git (site/content/docs/oap-agent.mdx:182). The real distribution path is an .oap bundle (packaging-oap.mdx:22). The card body (Landing.tsx:143, "kept in git") makes the same claim.
  • "own pod · budget · memory": pods ✅ (agentsession/podspec.go:320-322; really several per session). Budget ✅ (agentsession_types.go:60-63). But memory also lives at user scope (pkg/memory/userscope.go:13) and resource scope (resourcescope.go:9), beyond the session. The docs' own phrase is "its own workspace, its own budget, and its own audit trail" (agentclass-agentsession.mdx).

Suggested: "in git" becomes "versioned YAML" (or "reviewed · pinned"). The footer becomes "own pods · budget · audit trail".

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 938c9e5. "in git" becomes "versioned" (we're avoiding a YAML connotation), and the footer becomes "own runtime · budget · audit trail". The card body and aria label now match.

Comment thread site/app/(landing)/geo/figures.js Outdated

/* Carry: a scheduled run, a GitHub webhook, a Slack thread. Each wakes a session. */
{
const src = [[70, 108, "cron"], [70, 200, "github"], [70, 292, "slack"]], seq = [0, 1, 0, 2], tx = 300, tb = 236, th = 104;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Misleading] Channels figure: there's no cron channel kind

The channel kind enum is fake;slack;bento;local;browser;github;agent (pkg/apis/v1alpha1/channel_types.go:49). Scheduled runs are the bento kind (pkg/channels/channelkinds/bento/kind.go:1-3, "Cron-style triggers without a human user"). Calling a schedule a channel is accurate. "cron" just shouldn't read like a kind name.

GitHub and Slack waking sessions is accurate (github/kind.go:215-218, slack/kind.go:466-469).

Suggested: label it "schedule". Update the aria label in Landing.tsx (L187) to match: "A schedule, GitHub and Slack each wake a session".

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 938c9e5. The source is labeled "schedule", and the aria label reads "A schedule, GitHub and Slack each wake a session".

Comment thread site/app/(landing)/geo/figures.js Outdated
});
b += `<path class="i" d="${triD(gate, 238, 84)}" style="fill:var(--card)"/><path data-k="hole" class="i" d="${holeD(gate, 238, 84)}"/>`;
b += agent(ag[0], ag[1], 17) + `<circle data-k="m" class="pf" r="4" cx="-10" cy="-10"/>`;
b += T(ag[0] - 36, ag[1] - 32, "company:acme", "ac", "start") + Tk("vd", gate, 270, "", "", "middle");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Misleading] Memory figure: company:acme, and "one slot"

  • company isn't a type in the shipped schema. The shipped example uses crm_company (examples/hubspot-companies/manifests/mcpserver.yaml:92), and tests use crm_company:acme (pkg/authz/guardian/schema/slots_test.go:31-32).
  • A session isn't committed to exactly one slot. It reads the pool of every resource it holds a slot grant on (pkg/memory/pools/reader.go:41-48). Refusing an unheld resource is accurate (search/searcher.go:56-74, memory/approval.go:85-100), and so is "reading memory is a check" (spicedbauthorizer/authorizer.go:186-258).

Suggested: use crm_company:acme (and the same prefix for the slabs). Change the aria label (Landing.tsx L196-197) to "A session reads the memory of resources it's bound to; reading one it holds no grant on is refused".

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 938c9e5. The agent label is now the plainer "bound to acme", and the aria label reads "A session reads memory only for the resources it's bound to; reading another is refused".

Comment thread site/app/(landing)/geo/figures.js Outdated

/* Problem: one agent holding everyone's access, each call needing one slice. */
{
const D = 76, R = 46, users = ["maya", "jon", "priya", "sam", "leo"];

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Minor] Union figure shows a different problem than the copy beside it

The copy ("A token for one repository usually reaches every repository", which matches README.md:37-40) frames the problem as one credential broader than one task. The figure frames it as one agent holding the union of many people's access. Both are real, and the per-requester check is real (loop_subjects.go:218-243), but they're different problems shown side by side.

One caveat for any OAP-side copy: in the default agent identity mode, tools still authenticate with the agent's own credential. OAP's fix is that each call is checked against the person who asked, not that the agent acts as each user (site/content/docs/identity-modes.mdx). The subject also advances per turn, not strictly per call (loop_subjects.go:222-224).

Suggested: align one with the other. For example, change the copy to "A shared agent usually holds everyone's access at once, while each request comes from one person."

(The name "sam" is fine. Existing docs use it as a fictional requester, e.g. shared-permissions.mdx:29.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 938c9e5. The figure now follows the copy: the circles are repositories ("token reaches ∪ repos", "this task needs repo:api").

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Follow-up: ac78026 reworked this figure again. The label is now "token access: 5 repos"; all five access lines draw in, the one the task needs (api) lights, and the other four turn red as "unneeded access: 4 repos".

Address the accuracy review on the landing page redesign. The figures stay
conceptual, but no longer claim things OAP doesn't do:

- Depth: reorder layers to plan, slot, call check, tool spec, sandbox; the
  closing copy says the model never sees a credential.
- Broker: "handle" becomes "reference"; copy is framed around the model.
- Lens: labels follow left-to-right order, the person and agent sets read
  apart, and unattended the agent's full scope lights.
- Gate: gh api GET allowed, gh api -X POST denied.
- Define, channels, memory, union: plainer labels ("versioned", "own
  runtime · budget · audit trail", "schedule", "bound to acme") and the
  union figure now shows repositories to match its copy.
- Copy: sandboxes are per bundle, not per tool; bus credentials,
  pluggable parts and micro-VM scope are stated as they are.

README.md, docs/security-model.md and giving-credentials.mdx carried the
same credential and sandbox claims and are corrected to match.

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

samkim commented Oct 15, 2026

Copy link
Copy Markdown
Member Author

938c9e5 addresses the accuracy review. Each inline thread has a reply. The items from the review summary are done too:

  • "kept in git" (card body): now "a reviewable, versioned template".
  • "never through a shell": now "with no shell interpolation of arguments".
  • "the agent never holds them": now "the model never sees them".

A second pass over all rendered figures and copy found four more issues, all fixed:

  • "A sandbox per tool" (wrong). Sandboxes are per tool bundle, not per tool. The security card and the comparison row are now framed as "credentials injected for the tool that needs them, never shown to the model". README.md and docs/security-model.md are reworded the same way; the security-model section now says tools in one bundle share a sandbox.
  • Bus scope. "Every component gets its own bus credential, and a session's pods can publish only on that session's channels."
  • "Built in and swappable". The body now names only the parts that really plug in (model providers, sandbox backends, memory stores, channels, artifact storage). README.md gets the same change.
  • Micro-VMs. These apply to tool sandboxes only, not the operator.

The site checks (lint, typecheck, test, build) and mage fmt:check pass. The figures are still conceptual illustrations, and the depth figure keeps five layers as representative guards.

🤖 Generated with Claude Code

- Problem figure: lines show what the token can access. All five repos
  draw in, the one the task needs lights, and the other four turn red as
  unneeded access. Labels sit clear of their circles.
- Card bodies for Broker, Decide, Carry and Remember now carry the core
  idea of each primitive's definition: an agent acts as itself or for a
  person, the agent asks and never answers, every message and click is
  checked, and one store holds memory and a signed record.
- "Scroll to deal" becomes "Scroll to view".
- The OWASP lede points to each item's write-up instead of a disclaimer.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Comment thread docs/security-model.md Outdated
### Isolated sandboxes, credentials injected per tool

**Each tool runs in its own sandbox and holds only its own credentials.**
**Tools run in sandboxes apart from the agent, and a credential is injected only

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.

Tools run in sandboxes kept independent from the agent, and a credential is injected only for the specific tool that needs it - different tools do not see credentials for other tools

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Adopted in f8fe21c. The bold lead is your line, and the body now says a tool can be a tool bundle: operations talking to the same service share one sandbox and its credentials.

Take the reviewer's lead sentence: tools run in sandboxes kept independent
from the agent, a credential is injected only for the tool that needs it,
and different tools do not see each other's credentials. The body notes
that a tool can be a tool bundle, whose operations talk to one service and
share its sandbox and credentials.

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 b252622 into main Oct 19, 2026
10 checks passed
@samkim
samkim deleted the landing-page-redesign branch October 19, 2026 17:07
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