Skip to content

feat(landing): dev-focused rebuild — pinned examples, animated architecture, real cast#945

Merged
buremba merged 67 commits into
mainfrom
feat/landing-dev-focus
May 20, 2026
Merged

feat(landing): dev-focused rebuild — pinned examples, animated architecture, real cast#945
buremba merged 67 commits into
mainfrom
feat/landing-dev-focus

Conversation

@buremba
Copy link
Copy Markdown
Member

@buremba buremba commented May 19, 2026

Summary

Full rebuild of the lobu.ai home page across ~60 commits, in iterative rounds. Targets developers reading code, not operators picking use cases.

Highlights

Hero

  • Terminal-window chrome (macOS traffic-light dots) wrapping the asciinema player; `scaffold a lobu agent` label + `npx @lobu/cli@latest init my-agent` copy pill in the title bar (top-right)
  • Single agent cast (no toggle), 42s real recording of Claude Code scaffolding + validating a Lobu agent
  • Player waits 5s before autoplay, cancels if user hits play first
  • `Copy setup prompt` button copies a delegating prompt that asks Claude to install the lobu skill + scaffold

Architecture diagram (animated, flat)

  • 3 columns: `Connectors` (brand grid + `@lobu/connector-sdk` pill) → `Memory` (`events` box with subtle stream pulse → cron · LLM arrow → `entities` table widget) → `Agents` (chat-bots brand grid + Other-agents block + `@lobu/reaction-sdk` pill)
  • Respects `prefers-reduced-motion`
  • Stacks vertically below 1024px

Sections (pinned to real examples)

  • Connectors → `examples/ecommerce/connectors/stripe-charges.connector.ts` (universally readable REST + JSON, replaced earlier Linear GraphQL one-liner)
  • Memory → `examples/sales/models/schema.yaml` (entity types)
  • Watchers → `examples/sales/models/schema.yaml` (watcher) + `models/reactions/account-health-monitor.reaction.ts` (reaction)
  • Skills → `examples/office-bot/.../deliveroo-order/SKILL.md` (full frontmatter: `nixPackages`, `network.allow`, `network.judge`, `judges.default` policy)
  • Agents → `examples/sales/lobu.toml`
  • All snippets pulled by `scripts/gen-landing-snippets.ts` at build time + trimmed to fit without scroll
  • Every section ends with `Full example: examples/ →` GitHub link

Browse-examples grid — 12 cards auto-globbed from `examples/*/lobu.toml`. Drop a new example, the grid grows.

SDK docs — new `docs/getting-started/connector-sdk.md` + `reaction-sdk.md` (guides) and matching `docs/reference/` entries; sidebar updated; ProductLinks rewired.

Other

  • PostHog telemetry wired (was silently broken — Vite `envDir` was wrong; fixed in `7bcfbfd4`)
  • AI-slop copy pass (8 edits, terminology consistency)
  • BrowseExamplesSection auto-discovers via `glob examples/*/lobu.toml`
  • All deprecated/unused components deleted via knip
  • Mobile QA at 375 + 768 (overflow fixes in `c4740d66`)

What's deferred

Test plan

  • `bun run build` succeeds (85+ pages)
  • `bunx tsc --noEmit` clean
  • Mobile pass at 375 + 768
  • Architecture diagram + cast verified in Chrome
  • PostHog SDK fires `/capture` on home load
  • Pi review

Summary by CodeRabbit

  • New Features

    • Added eight example connectors (Discourse, Shopify, Stripe, QuickBooks, Linear, DocuSign, Exa News, Salesforce).
    • Major landing redesign: new architecture diagram, rewritten landing page, reusable CodeBlock UI, embedded asciinema playback and player stylesheet.
  • Documentation

    • Published Connector SDK and Reaction SDK getting-started guides and API references; added connector examples.
  • Chores

    • Added build-time snippet generator, updated site build/dev scripts and theme tokens, and adjusted repo config ignore patterns.

Review Change Stack

buremba added 30 commits May 19, 2026 16:19
Adds scripts/gen-landing-snippets.ts that walks examples/<id>/ for the
8 dev-focused use cases (legal, finance, sales, delivery, leadership,
agent-community, ecommerce, market) and emits
src/generated/use-case-snippets.json with the raw source of lobu.toml,
the entities + watchers sections of models/schema.yaml, and the first
reaction/connector TS file when present.

Wired into both prebuild and a new predev script so the manifest is
fresh whenever the landing page boots.
…lighting

New component renders Snippet objects from the use-case manifest with:
- tab header (filename + optional badge)
- syntax-highlighted body (regex tokenizers per language, no extra deps)
- optional maxLines cap with a fade gradient
- footer line-count + 'See on GitHub' link

Adds dark code-panel color tokens to globals.css tuned to harmonize with
the existing warm cream/orange page palette.
Each example now ships one realistic *.connector.ts modeled on
examples/lobu-crm/connectors/funnel-form.connector.ts:

- legal: docusign-envelopes (envelope status transitions)
- finance: quickbooks-transactions (bank-feed transactions)
- sales: salesforce-pipeline (opportunity changes)
- delivery: shopify-orders (order updates)
- leadership: linear-cycles (active-cycle issue transitions)
- agent-community: discourse-posts (forum posts)
- ecommerce: stripe-charges (charges + refunds)
- market: exa-news-feed (Exa neural-search articles)

The landing page reads these via gen-landing-snippets.ts so each
use-case pivot lands real connector code on screen.
Replaces the 3-stage HeroProductCard flow with a Notion-style dev-focused
home page mirroring the structure in tmp/lobu-mockup.html:

  Hero (copy-prompt CTA + Claude Code terminal demo)
  -> 3-box ArchitectureDiagram (External / Lobu / Memory)
  -> 'TypeScript + Postgres' pull-quote
  -> 'Three shapes' use-case grid
  -> Use-case pivot strip (8 tabs)
  -> Connectors  (code: connectorTs)
  -> Memory      (code: memorySchemaYaml)
  -> Watchers    (code: watcherYaml + WebhookFanDiagram)
  -> Agents      (code: agentToml + reactionTs)
  -> Run anywhere (3 cards)
  -> CTA + latest blog + footer

New components:
- WebhookFanDiagram: SVG fan-in/fan-out built from a per-use-case
  triggers + actions table; highlights one hot path
- ArchitectureDiagram rewritten as three monospace boxes
- LandingPage drives 4 product sections from
  generated/use-case-snippets.json (real example/<id>/ source)

Preserves Nav, Footer, CTA, LatestBlogPosts.
…ne tabs

Architecture diagram now reads 'external platforms / lobu / knowledge
graph' — three boxes on the same surface, same radius, same border,
all lowercase monospace. Lobu box has a slightly stronger border to
emphasise the central role; no shadows, no badges, no inner box
outlines (gateway/workers are just labelled lists).

WebhookFanDiagram is now a flat 3-column SVG (trigger rows / center
webhook / action rows). One trigger + one action highlighted with the
foreground colour, others sit in the muted border colour. No gradients,
no glow, no accent pills.

LandingPage:
- Use-case pivot becomes a Notion-style bottom-underline tab strip.
  Active tab: bold foreground text + 2px underline; inactive: muted.
- Drop drop-shadows from hero terminal, use-case grid cards, and
  run-anywhere cards.
- Callout simplified to a left-border-only quote (no fill).

CodeBlock loses its drop-shadow + accent-pill badge; the badge slot
becomes a muted lowercase comment in the tab. Drops  and the
fade-gradient truncation pattern (round 3 wants every code block to
render its source in full).

Drops the now-unused --color-landing-callout-* tokens from globals.css.
Adds optional `forceTheme` prop to BaseLayout, threaded into the inline
theme script as an early branch. When set, the script applies the matching
palette and returns before checking prefers-color-scheme.

Home page (`/`) opts into `forceTheme="light"` so the warm cream + orange
palette renders regardless of OS dark-mode. Other pages (docs, blog, etc.)
continue to honour the OS preference.
knip confirms these have no remaining importers anywhere in the package
(MDX, Astro pages, other components):

- ArchitectureSection.tsx (replaced by ArchitectureDiagram inline in LandingPage)
- FeatureBlock.tsx        (the old Memory + Skills feature rows)
- FeatureGraphics.tsx     (SharedMemoryGraphic + SkillsGraphic)
- HeroProductCard.tsx     (3-stage hero card flow)
- HeroSection.tsx         (the surrounding hero shell)

No backwards-compat shims per repo conventions — if it's unused, delete it.
…scroll

Round 3 requirement: every landing code block renders its source in full.
gen-landing-snippets.ts now does the trimming so the runtime can drop
maxLines + the fade-truncation pattern.

Per-snippet extraction rules:

- lobu.toml -> trimAgentToml() keeps the [agents.<id>] table, the first
  [[agents.<id>.providers]] block, and [memory]. Drops the dir= line,
  network rules, and the leading docstring comment. (Fixed the section
  regex to allow hyphens in agent ids: [agent-community], [vc-tracking].)
- models/schema.yaml entities slice -> first 2 entities with description /
  icon / color / x-* / enum / namespace / normalize stripped; properties
  capped at 4 keys per entity, with a trailing '# ...N more' comment when
  pruned.
- models/schema.yaml watchers slice -> first watcher only; block-scalar
  prompts collapsed to a single-line literal; sprawling extraction_schema
  bodies trimmed to type + required + first 4 property names.

Line counts (was -> now):
  agentToml:  24      -> 16
  memory:    73-393   -> 27-37
  watcher:   31-222   -> 11-24
  reaction:  unchanged (~40)
  connector: unchanged (handled separately)

Connectors still warn at 143-166 lines — addressed in the next commit
by slimming the source files themselves.
…scroll

Each *.connector.ts now under ~50 lines (was 140-170) so the landing
code block renders the full source in one visible chunk on a normal
viewport. Dropped:

- file-level docstring headers
- separate Config / Checkpoint interface aliases
- explicit configSchema / optionsSchema / eventKinds / metadataSchema
  payloads (the connector definition reduces to key + name +
  description + authSchema + a minimal feeds map)
- AbortController + per-request fetch timeout (one fetch, one response)
- standalone helper methods + stripHtml utility (inlined where used)
- the no-op execute() override (default implementation suffices)
- multi-line type aliases collapsed to a single line

The trimmed files still typecheck against @lobu/connector-sdk and
implement a real sync() that fetches, maps to events, and returns a
checkpoint — picking option (b) from the round-3 brief so there's one
source of truth, not a hand-curated landing-slim variant on the side.

Per-snippet line counts after this commit: 38-46 (was 143-166).
Two stragglers (leadership 45, market 46) still render without an
internal scrollbar at 1280x800; the gen-landing-snippets script warns
on anything > 40 to make future drift visible.
…tors

Biome's pre-commit hook reflowed the single-line type aliases and inline
authSchema fields in the 8 connector files back into multi-line form,
bumping each connector from ~40 lines to 48-60. The runtime CodeBlock
still renders without an internal scrollbar at 1280x800 but the JSON
manifest needs to match the on-disk source.
Absorb the landing's SETUP_PROMPT interview into the skill so installing
the skill is sufficient for an agent (Claude Code, Cursor, etc.) to
walk a new user from zero to a working Lobu agent. Standardises on
`npx @lobu/cli@latest init` (not the contributor monorepo clone).

Four phases: environment (Node 22-24, Postgres+pgvector, provider key),
interview (6 questions, one at a time, no batching), scaffold (CLI init
+ targeted edits), verify (concrete search_memory check + admin UI URL).
…8, connectors ~32

Round 4 brief said snippets are still too long. Re-tuned both the
generator and the connector source files:

gen-landing-snippets.ts:
- trimAgentToml() drops blank-line separators between sections and the
  [memory] description / [agents] description / dir fields. Result: a
  flat 11-line table (was 13 with blanks, 16 with descriptions).
- compressEntities() now emits ONE entity with at most 3 properties,
  each rendered as a single-line `<name>: { type: <t> }` shorthand,
  dropping all nested x-table / enum / description metadata. Result:
  10 lines (was 27-37).
- compressWatcher() renders slug + agent + on|schedule + a single-line
  prompt + extraction_schema.type + required (a single bracketed list,
  not the full property graph). Only the FIRST top-level `required:`
  is harvested — nested required: arrays inside object properties
  no longer leak into the snippet (fixed market). Result: 8 lines
  (was 11-24).
- Fixed indent math: children of '- slug: …' live at baseIndent+2 (the
  source uses 2-space YAML indent), and the body of metadata_schema /
  extraction_schema lives at +4 / +6 respectively.

Connector source files (all 8):
- One-line `import { ConnectorRuntime, type SyncContext }`
- `readonly definition` without explicit ConnectorDefinition typing,
  with the inline payload narrowed to key + name + version + authSchema
  + a single-feed feeds map. No description, no eventKinds, no
  configSchema, no optionsSchema, no per-field metadataSchema.
- `sync(ctx: SyncContext)` — no Promise<SyncResult> annotation; ctx
  fields accessed directly. Inline anonymous response types.
- Minimal no-op execute() so ConnectorRuntime's abstract contract is
  satisfied with one line.

Result: connectors land at 31-38 lines (was 48-60 after round 3,
148-166 originally). Budget bumped to 40 to account for biome's
preferred line wrapping.
…l format

Round 4 follow-up: after biome reformatted the round-4 connector
rewrites back from ~32 to 46-60 lines (it expanded inline anonymous
response types and the authSchema methods array onto separate lines),
add the file-level pragma // biome-ignore-all format at line 1 of every
connector so biome leaves the compact layout alone on subsequent runs.

Also replace the per-call inline response types with a single `as any`
cast on the json() result, then narrow back at the destructure site
(`const records: any[] = …`). Loses some compile-time type info on the
remote response but the events the connector emits are still strongly
typed via the connector-sdk contract.

Per-connector line counts on disk: 32-34 (was 46-60).
Each primitive section (Connectors / Memory / Watchers / Agents) now
pairs the code block with a faked terminal transcript on the same side.
The terminal shows what running the primitive looks like for the active
use case — e.g. for sales the connectors terminal reads:

  $ lobu run
  → connector  salesforce-pipeline   ✓
  → synced     3 opportunities       142 ms
  → event      salesforce.opp.updated #acme-q4

New files:
- TerminalPanel.tsx — flat dark panel with the dot title bar and a
  hand-built sequence of tagged segments (plain / muted / accent /
  string / key / green). Same styling as the hero terminal.
- terminal-outputs.ts — 8 use cases × 4 sections of transcripts,
  authored via small tagged helpers (`p`, `muted`, `accent`, …) so
  the data block stays compact.

LandingPage changes:
- All 4 product sections now pull the per-section terminal from
  TERMINAL_OUTPUTS[useCaseId][section] and render it under the
  CodeBlock.
- Drops the Callout component (no longer used) and the now-orphaned
  WebhookFanDiagram (the watcher terminal already shows trigger →
  watcher → extracted → event textually).
- AgentsSection drops the inline reaction.ts CodeBlock — viewers can
  reach it via the connector's 'see on github' link if they want to
  read the full file.
Hero now mounts a playing asciinema cast instead of a hand-coded React
terminal — frees up that real estate for an actual recording.

Wiring:
- BaseLayout.astro takes a new loadAsciinema?: boolean prop. When true
  it ships the vendored CSS in <head> and the standalone .min.js bundle
  before </body>. Files live in packages/landing/public/asciinema-player/
  (added with -f to defeat the packages/**/*.js gitignore rule).
- biome ignore extended with !**/packages/landing/public/** so the
  pre-commit hook doesn't try to lint the minified player.
- index.astro passes loadAsciinema={true} so the player only ships on
  the home page; docs / blog don't pay for the bundle.
- LandingPage HeroAsciinema() renders a flat dark container with a
  ref callback that calls AsciinemaPlayer.create("/casts/setup.cast",
  node, { autoPlay, loop, idleTimeLimit, fit, theme }) once on mount.
  Guarded via dataset.asciinemaMounted so HMR doesn't double-mount.
- public/casts/setup.cast — placeholder cast (asciicast v2) that
  walks the same scaffold flow the old React terminal showed. Drop
  the real recording at this path when ready.

Drops the HeroTerminalDemo function entirely; restores the period on
the hero headline that biome lost in the prior reflow.
The skill (`/plugin install lobu`) absorbs the env-setup + interview +
scaffold flow that was previously inlined in the hero's copy-prompt
button. Landing's prompt is now a three-step ask:

  1. install the skill
  2. run the skill's onboarding interview (asks what / who / data /
     channels / schedule)
  3. scaffold + boot locally and show the written memory event

Plus a one-paragraph orientation line + repo / docs URLs so an
unprimed Claude / Cursor / opencode session still gets enough context.

Drops the 30-line hand-rolled phased prompt — the skill is the source
of truth for project conventions now.
…block

No behavior change; biome's pre-commit hook reflowed long single-line
expressions over multiple lines in three files left uncommitted from
round 4. Committing so subsequent diffs stay readable.
Round 5 user feedback. Tightens prose where the rhythm read like AI
output without losing the underlying claim.

- Drop the entire PullQuote section ('If you know TypeScript and
  Postgres…' + 'No new language…') — call site and component both gone.
- UseCaseGrid heading: 'Three shapes. One platform.' → 'Three ways
  teams ship Lobu agents.'
- Connectors SectionHeading: 'One event stream for everything your
  team produces.' → 'One typed event stream from every source.'
- Hero subhead: drops the three-parallel-sentence cadence; adds
  'search and cite' as the concrete capability.
- UseCase card 1 (For your team): swaps the 'One-click "Add to Slack"
  wires the bot live' marketing line for the matter-of-fact 'Add the
  bot to Slack from the admin UI'.
- UseCase card 2 (For your org): replaces 'Dreaming watchers deepen
  the graph nightly. No manual ETL.' with the more concrete 'Watchers
  run on cron to add structure overnight, so the schema grows with
  your data.'
- Watchers feature list 'Dreaming' item: drops 'while your team
  sleeps'; collapses 'yesterday's events' to 'the previous day's
  events'.
- Agents feature list 'Ship anywhere' item: replaces the empty
  one-liner with the actual list (Slack/Telegram/Discord/Teams/
  WhatsApp/HTTP/MCP) + 'Same lobu.toml'.

Hero H1 ('Proactive AI agents on self-building knowledge graph') and
the watchers callout (already deleted in round 4) left as-is per the
amended brief.
- Drop `forceTheme="light"` on the home page; honor user's system
  preference like the rest of the site.
- Re-remove the period from the hero headline that the round-5 copy
  pass reverted.
Each primitive section's right column was a faked terminal transcript.
Round-6 swap puts the tables that used to live in the deleted
HeroProductCard (round 2, commit e661f98) back in their place — same
data shape (LandingUseCaseDefinition), same flat composition rules from
round 2 (no shadows, no gradients, lowercase-mono headers,
--color-page-border + --color-page-surface).

New file packages/landing/src/components/AppShellPanels.tsx (439 lines)
exports four panels, each wired into the matching section in
LandingPage:

- ConnectorsPanel  -> ConnectorsSection (collapsible per-connector
  rows with sample connections under the active row; dedupes by
  brand-key so github.com + .githubusercontent.com collapse)
- MemoryPanel      -> MemorySection (entity-type chips strip on top,
  then first 4 records from useCase.memory.recordTree.children)
- WatchersPanel    -> WatchersSection (slug + entity + status badge +
  cron schedule + last run; reuses buildWatcherRows shape from the
  deleted file)
- AgentsPanel      -> AgentsSection (agent name + channel + skills
  chips + status; synthesized from skills.agentId / skills.skills /
  memory.watcher.name)

Each panel wraps in a shared PanelFrame that gives the dot-titlebar
look (accent eyebrow on the left, /route on the right) without
re-introducing the dark code-bg from TerminalPanel.

Watchers section keeps WatchersPanel only — the WebhookFanDiagram had
already been deleted in round 4 commit 558d7b2, and the table tells
the trigger/entity/schedule story cleanly enough on its own.

Drops terminal-outputs.ts + TerminalPanel.tsx entirely; no section uses
them anymore.
…amples

User feedback: card 3 was off-positioning (Lobu = org/team backend, not
B2B SaaS LLM-embed). New framing: every card is a technical shape of a
Lobu agent, each backed by a real examples/<id>/ project.

- SectionHeading: 'Three ways teams ship Lobu agents.' ->
  'Three shapes. Three working examples.'
- Card 1: Reactive bot / A chat-driven agent. -> office-bot example
- Card 2: Cron digest / A dreaming watcher. -> finance example
- Card 3: Event automation / A connector -> watcher -> reaction
  pipeline. -> sales example

Snippet styling unchanged (same monospace mini-block, same code-bg +
comment/key/string tokens). Links keep target=_blank +
rel=noopener noreferrer as before.
User: 'maybe let's just remove for now.' The synthesized rows
(buildSampleConnections -> Albert Lund / 2m ago / lobu-prod.workspace)
felt dishonest as a Lobu Cloud preview; we may swap in real screenshots
later.

- Drop imports for ConnectorsPanel / MemoryPanel / WatchersPanel /
  AgentsPanel + the landingUseCases import that fed them.
- Strip the panel render from each of the 4 product sections; right
  column is now just the CodeBlock. ProductGrid layout (text + code,
  alternating reverse) unchanged.
- Delete packages/landing/src/components/AppShellPanels.tsx (439 lines).

knip on packages/landing reports only pre-existing orphans
(functions/*, starlight-*.css, asciinema-player.css) — no leftover
panel callers.
User: 'above agents maybe we can have one more section called skills.'
Lands SkillsSection (reverse grid, code on left, text on right) so the
new section flow reads:

  Hero -> Architecture -> UseCaseGrid -> Pivot -> Connectors ->
  Memory -> Watchers -> Skills -> Agents -> Run anywhere -> CTA -> Posts

Section content:
- Eyebrow: 'Skills'
- Heading: 'Bundle tools, packages, and policy into one drop-in.'
- Lede + 4-item FeatureList (Instructions / Tools / Network / Packages)
- ProductLink 'Read the skills guide' -> /getting-started/

Code panel:
- Static CodeSnippet (not pivoted — only lobu-crm + office-bot ship
  SKILL.md today). Holds the YAML frontmatter + '# CRM operations' +
  first paragraph of examples/lobu-crm/agents/crm/skills/crm-ops/SKILL.md.
- tabLabel = agents/crm/skills/crm-ops/SKILL.md
- badge = 'skill'
- githubUrl points at the file on main.

CodeBlock now supports markdown language:
- Tokenizer recognises the leading '---' frontmatter fences, frontmatter
  'key: value' pairs (key + string colour), ATX headings (# … through
  ###### …), and inline backtick code spans. Everything else falls
  through as plain text.
The crm-ops/SKILL.md frontmatter only carried name+description, which
didn't back the section's 'bundle tools, packages, and policy' pitch.
Swap to office-bot/agents/food-ordering/skills/deliveroo-order — its
frontmatter exercises every promised field:

  - nixPackages: [chromium]
  - network.allow (registry.npmjs.org, playwright.azureedge.net)
  - network.judge (deliveroo.co.uk, deliveroo.com)
  - judges.default — plain-English egress policy that allows reads +
    basket mutations and DENIES checkout/payment

Description and judges.default policy trimmed to keep the snippet at
19 lines (was 30+ in source). H1 + first paragraph dropped — the
frontmatter alone makes the pitch and there's no room to scroll on the
right column.

tabLabel updated to agents/food-ordering/skills/deliveroo-order/SKILL.md;
githubUrl points at the file on main; language stays markdown so the
tokenizer keeps colouring frontmatter keys, the --- fences, and the
inline backtick code spans (`lobu apply`, etc.).

Body lede tweaked: 'instructions, tools, network, and packages' ->
'instructions, tools, packages, and a per-domain LLM egress policy'
so the prose matches what the new snippet actually demonstrates.
User: the 8-tab pivot at the top forced the reader to scroll back to
remember which use case they picked. Pin every primitive section to a
canonical example instead.

- Delete PIVOT_USE_CASES constant + UseCasePivot component + its
  render call.
- Delete activeUseCaseId state, defaultUseCaseId prop, the
  LandingUseCaseId / DEFAULT_LANDING_USE_CASE_ID imports.
- Replace with a module-level PINNED_USE_CASE = 'sales' and a single
  derived 'active' snippet bundle, fed to every section.
- Drop the now-unused useCaseId field from ProductSectionProps; sections
  take just { useCase }.

Following commits (Task B + C) will move the snippet manifest to per-
section pinned files instead of per-use-case bundles.
Round 10 Task B + amendment. New manifest shape:

  {
    connector:    Snippet,   // examples/lobu-crm/connectors/funnel-form.connector.ts
    memorySchema: Snippet,   // examples/sales/models/schema.yaml (entities slice)
    watcher:      Snippet,   // examples/sales/models/schema.yaml (watchers slice)
    reaction:     Snippet,   // examples/sales/models/reactions/account-health-monitor.reaction.ts
    agentToml:    Snippet,   // examples/sales/lobu.toml
    examples: ExampleEntry[] // every examples/*/lobu.toml — globbed, not hardcoded
  }

Each ExampleEntry has slug + label + description + githubUrl. Label
comes from [agents.<id>] name; description from [memory] description
(falling back to [agents.<id>] description); both pulled by a small
readExampleMeta() parser. Missing description -> null (component
renders the card without a description line).

Drops the round-4 use-case slicing — no more buildForUseCase(useCase),
no more USE_CASES enum. Per-snippet trimming logic kept intact for the
pinned files. Output file path renamed to landing-snippets.json so the
landing import switches cleanly in Task C.

Also slims examples/lobu-crm/connectors/funnel-form.connector.ts from
179 lines to 39 (same // biome-ignore-all format + as any pattern used
for the 8 round-4 connectors) so the pinned connector snippet fits the
landing without scroll.

12 examples land in the manifest (agent-community, atlas, delivery,
ecommerce, finance, leadership, legal, lobu-crm, market, office-bot,
personal-finance, sales) — every directory under examples/ that has a
lobu.toml. Sorted alphabetically by slug.
…le footer links

Task C of round 10.

- Switch import: ../generated/use-case-snippets.json ->
  ../generated/landing-snippets.json (flat pinned-snippet shape from Task B).
- Drop UseCaseSnippets / ProductSectionProps types; sections take no
  props and reach into snippets.<key> directly.
- New ExampleFooterLink helper renders 'Full example: examples/<slug> →'
  in muted text with the slug in monospace + accent on hover.
- ConnectorsSection: pulls snippets.connector (funnel-form), footer
  -> examples/lobu-crm.
- MemorySection: pulls snippets.memorySchema (sales entities), footer
  -> examples/sales.
- WatchersSection: TWO code blocks stacked — watcher YAML, then a
  one-line label 'When the watcher extracts data, this reaction runs:',
  then snippets.reaction (account-health-monitor.reaction.ts). Footer
  -> examples/sales.
- SkillsSection: footer -> examples/office-bot.
- AgentsSection: drops the reaction.ts CodeBlock (it lives with the
  watcher now), keeps just snippets.agentToml. Footer -> examples/sales.

Each section's right column now reads top-to-bottom: code -> (optional
extras) -> footer link, so the reader always knows which example
they're looking at.
…isted)

Task D of round 10 + amendment.

- Drop UseCaseGrid (3 'shape' cards) entirely.
- New BrowseExamplesSection renders one card per examples/ project from
  snippets.examples (populated by glob in gen-landing-snippets.ts in
  Task B). Today: 12 cards (agent-community, atlas, delivery, ecommerce,
  finance, leadership, legal, lobu-crm, market, office-bot,
  personal-finance, sales), all auto-sorted by slug.
- Section position moves down: between AgentsSection and
  RunAnywhereSection, so the reader sees the primitives first and the
  catalog last.
- Card shape: flat (border + bg-surface, no shadow), the whole card is
  one <a target=_blank href=githubUrl>, monospace slug at top, optional
  one-line description from lobu.toml below.
- Grid: 1 column on mobile, 2 at sm, 3 at md+.
- Section header: eyebrow 'Browse the repo' + heading 'Examples' +
  sub-lede.

Per the amendment: no hardcoded list — gen-landing-snippets emits the
examples[] array so adding a new project under examples/ just lands a
new card without touching this file.
Replaces the hand-scripted 9-frame placeholder with a real asciicast
of `lobu init my-agent` followed by `ls` + `cat lobu.toml`. Output
is genuine CLI output; the "npx @lobu/cli@latest …" header is
printf'd for marketing readability (locally-installed `lobu` is what
actually runs to avoid the bunx download noise in the cast).
buremba added 7 commits May 19, 2026 23:49
End the cast right after `lobu.toml is valid` instead of running on
into the `lobu run` env-bug debug spiral (which ends in Claude
hallucinating a bot response in the summary). Honest beat: scaffold
the project, validate it, done. `lobu chat` end-to-end demo will
return once the CLI bug-fix branch lands + we record cleanly with
fixed env.
End the cast right after Claude's 'Validated successfully' status —
before it gets into the lobu run env-bug debug spiral that ends with
a hallucinated bot response in the summary. Honest beat: paste prompt
→ Claude scaffolds → schema written → lobu validate succeeds → end.
The lobu chat end-to-end demo returns once the CLI bug-fix branch lands
and we record with a stable BETTER_AUTH_SECRET env.
The previous Linear GraphQL connector showed a wall of minified
GraphQL as a template string that's cryptic for a developer who
hasn't worked with Linear. Stripe charges is universally recognized
and the snippet shape is plain REST fetch + JSON.map, much easier to
read at a glance. Also update the Connectors-section footer link to
point at examples/ecommerce.
Adds guide-style entries under getting-started/ and full type references
under reference/ for both @lobu/connector-sdk and the reaction surface,
points the landing's Connectors/Watchers ProductLinks at them, and
surfaces them from the REST API reference splash + platforms/rest-api.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

Adds multiple Connector SDK example runtimes, a manifest-driven landing redesign (snippet generator, CodeBlock, ArchitectureDiagram, LandingPage), asciinema assets and layout/theme updates, and Connector/Reaction SDK getting-started and reference documentation.

Changes

Example Connector Implementations

Layer / File(s) Summary
Connector SDK examples and config
config/biome.config.json, examples/*/connectors/*.connector.ts
Adds multiple example connectors (Discourse, Shopify, Stripe, QuickBooks, Linear, DocuSign, Exa, Salesforce) each with definition, sync() to fetch and emit events while advancing checkpoints, and execute() stubs. Simplifies FunnelForm connector. Updates biome ignore includes for skills and landing public assets.

Landing Page Redesign

Layer / File(s) Summary
Build-time snippet generation
packages/landing/scripts/gen-landing-snippets.ts, packages/landing/package.json
New Bun/Node generator reads pinned example sources, compresses/transforms TOML/YAML/MD/TS into budgeted snippet entries, emits landing-snippets.json, and is wired into predev/prebuild scripts.
CodeBlock component
packages/landing/src/components/CodeBlock.tsx
New CodeBlock with internal tokenizers for TOML, YAML, TypeScript, and Markdown; renders syntax-highlighted, line-preserving snippets with header/footer and GitHub link.
Architecture diagram rewrite
packages/landing/src/components/ArchitectureDiagram.tsx
Replaces previous diagram with layered "Connectors → Memory → Agents" layout, connector glyphs, responsive boards, StreamBox pulsing UI, EntitiesTable, DerivationArrow, and arrow components.
Landing page implementation
packages/landing/src/components/LandingPage.tsx
LandingPage rewritten to load the generated manifest and render static sections (Hero with clipboard and Asciinema mounting, ArchitectureDiagram, Connectors/Memory/Watchers/Skills/Agents with CodeBlocks, BrowseExamples, RunAnywhere, CTA).
Layout, navigation, and component cleanup
packages/landing/src/components/Nav.tsx, packages/landing/src/layouts/BaseLayout.astro, packages/landing/src/styles/theme-script.ts, packages/landing/src/pages/*.astro
BaseLayout gains forceTheme/loadAsciinema; Nav removes startUseCaseId and related start-URL logic; theme-script supports forced theme; pages updated to pass loadAsciinema. Several old components removed (ArchitectureSection, HeroSection, FeatureBlock, FeatureGraphics).
Configuration, assets, and styling
packages/landing/astro.config.mjs, packages/landing/public/asciinema-player/asciinema-player.css, packages/landing/src/globals.css
astro.config adds Connector/Reaction SDK sidebar links and sets Vite envDir to repo root; adds a 711-line asciinema-player stylesheet; globals.css adds landing code-block theme tokens.

SDK Documentation

Layer / File(s) Summary
Connector and Reaction SDK guides
packages/landing/src/content/docs/getting-started/connector-sdk.md, packages/landing/src/content/docs/getting-started/reaction-sdk.md
Adds detailed getting-started guides for connectors and reactions: connector runtime shape, idempotent checkpoints, auth models, reaction signature and injected client, examples, and wiring rules.
API reference documentation
packages/landing/src/content/docs/reference/connector-sdk.md, packages/landing/src/content/docs/reference/reaction-sdk.md
Connector SDK reference documents ConnectorRuntime, definitions, auth variants, feed/entity wiring, sync/action contracts, interactive auth artifacts, admin models, and helper exports. Reaction SDK reference documents reaction signature, ReactionContext/entity shapes, injected client APIs, and execution lifecycle.
Platform documentation
packages/landing/src/content/docs/platforms/rest-api.md, packages/landing/src/pages/reference/api-reference.astro
REST API docs now reference TypeScript SDKs for in-project usage. API reference adds "Other references" quicklinks and related styling.

Estimated code review effort:
🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • lobu-ai/lobu#737: Overlaps landing hero/stage and LandingPage/Hero component changes.
  • lobu-ai/lobu#744: Overlaps LandingPage memory/skills copy and feature-block changes.

🐰 Eight connectors hop into the stream,

Code blocks shimmer with a syntax dream,
Memory pulses, agents hum along,
Landing blooms with docs and song. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: a developer-focused landing page rebuild with pinned examples, animated architecture, and a real terminal cast.
Description check ✅ Passed The description covers all required sections: Summary (why), Highlights (what changed), Test plan (validation), and Notes (deferred work). It comprehensively documents the changes across hero, architecture, sections, and SDK docs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/landing-dev-focus

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 18

🧹 Nitpick comments (1)
packages/landing/scripts/gen-landing-snippets.ts (1)

536-541: 💤 Low value

Hardcoded policy summary replaces actual content.

The collapsed default: value is a fixed string regardless of what the actual skill policy says. This is fine for demo purposes but could be misleading if the pinned skill's policy differs significantly. Consider extracting the first sentence from the actual block scalar instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/landing/scripts/gen-landing-snippets.ts` around lines 536 - 541, The
code always inserts a hardcoded default policy string when matching the YAML
block scalar (regex assigned to blockScalar) which can misrepresent the actual
skill policy; instead, parse the matched block scalar lines following the
detected indent (use baseIndent and the surrounding lines or the original block
scalar content) and extract the first sentence of that block scalar to produce
the summary inserted by out.push for the default: entry, preserving indentation
via " ".repeat(baseIndent) so the inserted line reflects the real policy rather
than a fixed message.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/agent-community/connectors/discourse-posts.connector.ts`:
- Around line 14-16: The current cursor/window logic uses before=${cursor + 50}
and then filters id > cursor which can permanently skip posts if >50 new posts
arrive; replace that with a proper "since" style fetch and pagination: request
posts using after=${cursor} (or iterate fetching pages until no posts > cursor)
and remove the id>cursor post-filter, updating the checkpoint to the highest
returned post id (reference variables: cursor, ctx.checkpoint, the fetch call).
Also include the configured API key from your connector auth (use
ctx.secrets?.api_key or the authSchema key) in the request (e.g., add an Api-Key
header or query param when calling fetch against ctx.config.base_url) so
authentication is actually sent. Ensure to update the fetch invocation and
checkpoint handling in the same function accordingly.
- Around line 9-15: The sync method is calling fetch without using the declared
api_key in authSchema, so private Discourse instances will fail; update the
sync(ctx: SyncContext) implementation to read the configured api_key (from the
connector auth/secrets available on ctx, e.g. ctx.config.auth or ctx.secrets)
and attach it to the request—either by adding an Api-Key header or appending
?api_key=... to the URL—when calling
fetch(`${ctx.config.base_url}/posts.json?...`) so the declared authSchema is
actually applied; ensure the key name matches "api_key" and handle missing key
gracefully.

In `@examples/delivery/connectors/shopify-orders.connector.ts`:
- Around line 9-16: The sync function is not using the access_token declared in
authSchema; update sync to read the token from ctx.auth or ctx.config (where
auth is stored) and include it as the Authorization header (Bearer
<access_token>) or as X-Shopify-Access-Token per Shopify API when performing
fetch to orders.json; modify the fetch call in sync to add the appropriate
header and ensure it throws or logs a clear error if access_token is missing,
referencing authSchema and the sync function so reviewers can find the change.

In `@examples/ecommerce/connectors/stripe-charges.connector.ts`:
- Around line 15-16: The current single-page fetch using
fetch(`https://api.stripe.com/v1/charges?limit=100&created[gt]=${cursor}`) and
then advancing the checkpoint to the last returned record can drop records if
more than 100 charges exist; modify the connector to either (A) iterate
pagination until all pages are retrieved (use Stripe's next_page/has_more or the
response.data + starting_after/limit pattern) before sorting and advancing the
checkpoint, ensuring the loop references the same fetch call and the
response.data handling, or (B) switch the checkpoint to a cursor-based/offset
approach (store Stripe's starting_after/last_id or a composite timestamp+id)
instead of just the last record's created timestamp so no records are skipped
when updating the checkpoint. Ensure the code paths that read `cursor`, call
`fetch(...)`, and update the checkpoint (where the last record's created
timestamp is used) are updated accordingly.
- Around line 9-15: The fetch call in the sync method is missing the Stripe API
credential declared in authSchema: grab the secret_key from the connector
context (e.g., from ctx.connectorAuth or ctx.auth depending on how credentials
are stored in this runtime) and include it in the request as an Authorization:
Bearer header when calling fetch in sync; update the fetch invocation used in
sync (and preserve the existing cursor logic) to pass headers: { Authorization:
`Bearer ${secret_key}` } so Stripe requests authenticate properly.

In `@examples/finance/connectors/quickbooks-transactions.connector.ts`:
- Around line 14-16: The current checkpoint (ctx.checkpoint?.last_txn_date) and
query (TxnDate > since with MAXRESULTS 500) can skip same-day overflow; change
the checkpoint to include sub-day granularity (e.g., last_txn_datetime or a
tuple {last_txn_date, last_txn_id}) and update the query construction in this
connector where variables since, q and the fetch call are created: use a
timestamp field (MetaData.LastUpdatedTime or TxnDate with time) or a composite
filter to break ties (e.g., fetch transactions where TxnDate > last_date OR
(TxnDate = last_date AND Id > last_id)) so the next run includes remaining
same-day records, and when persisting the checkpoint save both the
datetime/timestamp or datetime+id so subsequent queries use the finer-grained
checkpoint.
- Around line 9-16: The fetch to QuickBooks in the async sync(ctx: SyncContext)
function is missing the OAuth Authorization header; update the fetch call that
builds the query URL for ctx.config.realm_id to include headers: pass
Authorization: Bearer ${ctx.credentials?.accessToken} (or
ctx.credentials.accessToken) and appropriate Accept/Content-Type as needed so
the request uses the OAuth token from SyncContext credentials; ensure you
reference the existing q variable and keep encodeURIComponent(q) when adding
headers to the same fetch invocation.

In `@examples/leadership/connectors/linear-cycles.connector.ts`:
- Around line 11-17: In the sync(ctx: SyncContext) function the GraphQL POST to
"https://api.linear.app/graphql" omits the OAuth token; read
ctx.credentials?.accessToken and add an Authorization: Bearer <token> header
when present (merge with existing "Content-Type" header) before calling fetch so
the Linear API request is authenticated.

In `@examples/legal/connectors/docusign-envelopes.connector.ts`:
- Around line 9-16: The sync method is calling the DocuSign API without using
the OAuth token declared in authSchema; update the fetch in sync to include an
Authorization header using ctx.credentials?.accessToken (e.g., headers: {
Authorization: `Bearer ${ctx.credentials?.accessToken}` }) and preserve existing
parameters (from_date, count) and base URL handling; ensure you handle missing
accessToken gracefully (throw or log) before making the request.

In `@examples/market/connectors/exa-news-feed.connector.ts`:
- Around line 15-16: The authSchema definition is incorrect and the connector
doesn't send the API key: change the authSchema object to use type: "env_keys"
and use key (not name) for the field definition (i.e., adjust the authSchema
entry for the Exa API key), and update the sync/fetch logic to read the
env-based credential instead of using ctx.credentials (which is OAuth-only) —
use the SDK's env_keys access pattern (or SyncContext.connection_credentials /
equivalent once exposed) to add the Authorization header to the POST fetch to
https://api.exa.ai/search so the API key is sent with each request.

In `@packages/landing/public/asciinema-player/asciinema-player.css`:
- Line 2: Update the CSS variable --term-font-family to quote all font family
names that currently are unquoted (e.g., wrap Menlo, Consolas, monospace entries
in quotes) and replace any deprecated word-wrap declarations with overflow-wrap
to satisfy Stylelint; search for the --term-font-family declaration and any
occurrences of word-wrap in asciinema-player.css and update the identifiers
accordingly.

In `@packages/landing/src/components/LandingPage.tsx`:
- Around line 346-417: HeroAsciinema's ref stores a cleanup function on
typedNode.__lobuHeroCleanup but never calls it, so timers and listeners leak;
update the ref callback inside HeroAsciinema to, before attaching a new
instance, check if an existing node was previously mounted (i.e., when ref is
called with null on unmount or when replacing the node) and invoke its
__lobuHeroCleanup if present, and also ensure you clear __lobuHeroCleanup after
calling it; reference the typedNode.__lobuHeroCleanup property and the ref
callback in HeroAsciinema to perform this cleanup invocation.

In `@packages/landing/src/components/Nav.tsx`:
- Around line 294-299: Remove the unused prop "currentPath": delete it from the
NavProps type and drop it from the Nav component signature (remove the default
"_currentPath = '/'"), leaving Nav as function Nav() and preserving the internal
state (e.g., openId via useState). Then remove the prop from every .astro
callsite (delete currentPath={Astro.url.pathname} occurrences) so callers match
the new signature, and run the type checker to ensure no remaining references.

In `@packages/landing/src/content/docs/getting-started/connector-sdk.md`:
- Around line 203-210: The fenced code block that shows the project tree (the
triple-backtick block starting at the snippet with "my-agent/") is missing a
language tag and triggers MD040; update that block to use the text language tag
by changing the opening fence from ``` to ```text so the tree snippet is fenced
as plain text.

In `@packages/landing/src/content/docs/getting-started/reaction-sdk.md`:
- Around line 100-109: The fenced filesystem snippet starting at the code block
should specify a language to satisfy markdownlint MD040; update the opening
fence from ``` to ```text so the block (showing the my-agent/ tree with
lobu.toml, models/, watchers/, reactions/, etc.) is explicitly marked as text.

In `@packages/landing/src/content/docs/platforms/rest-api.md`:
- Around line 24-25: Change the link text that reads "`@lobu/reaction-sdk`" to
make it clear this is a docs/reference page rather than an installable
package—e.g., replace the visible text "`@lobu/reaction-sdk`" with "Reaction SDK
reference" (while keeping the same href `/reference/reaction-sdk/`) so readers
don’t confuse the link label with an npm package; leave the
"`@lobu/connector-sdk`" text as-is unless you want it similarly clarified.

In `@packages/landing/src/content/docs/reference/connector-sdk.md`:
- Line 180: The in-page fragment link `#authartifact` in the sentence
referencing `AuthArtifact` is invalid because the actual section is a combined
heading; update the documentation so the fragment resolves: either add a
dedicated heading `### AuthArtifact` (so the `#authartifact` anchor becomes
valid) or change the link target to the exact generated anchor for the combined
heading (replace `#authartifact` with the correct anchor text). Ensure the
sentence still mentions `authenticate(ctx)` and streams `AuthArtifact`s and that
the link points to the newly created `AuthArtifact` heading or the correct
combined-heading anchor.

In `@skills/lobu/SKILL.md`:
- Line 34: Update the onboarding text that currently references "connector.ts"
to use the canonical pattern "connectors/<name>.connector.ts" so it matches the
rest of the guide; replace the occurrence of connector.ts in the SKILL.md
sentence with connectors/<name>.connector.ts and ensure wording remains
consistent with the later reference to connectors/<name>.connector.ts.

---

Nitpick comments:
In `@packages/landing/scripts/gen-landing-snippets.ts`:
- Around line 536-541: The code always inserts a hardcoded default policy string
when matching the YAML block scalar (regex assigned to blockScalar) which can
misrepresent the actual skill policy; instead, parse the matched block scalar
lines following the detected indent (use baseIndent and the surrounding lines or
the original block scalar content) and extract the first sentence of that block
scalar to produce the summary inserted by out.push for the default: entry,
preserving indentation via " ".repeat(baseIndent) so the inserted line reflects
the real policy rather than a fixed message.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c7d2574e-b10c-4720-ad63-dd46052e45f7

📥 Commits

Reviewing files that changed from the base of the PR and between 17f0da9 and 008f05d.

⛔ Files ignored due to path filters (4)
  • packages/landing/public/asciinema-player/asciinema-player-ui.min.js is excluded by !**/*.min.js
  • packages/landing/public/asciinema-player/asciinema-player-worker.min.js is excluded by !**/*.min.js
  • packages/landing/public/asciinema-player/asciinema-player.min.js is excluded by !**/*.min.js
  • packages/landing/src/generated/landing-snippets.json is excluded by !**/generated/**
📒 Files selected for processing (36)
  • config/biome.config.json
  • examples/agent-community/connectors/discourse-posts.connector.ts
  • examples/delivery/connectors/shopify-orders.connector.ts
  • examples/ecommerce/connectors/stripe-charges.connector.ts
  • examples/finance/connectors/quickbooks-transactions.connector.ts
  • examples/leadership/connectors/linear-cycles.connector.ts
  • examples/legal/connectors/docusign-envelopes.connector.ts
  • examples/lobu-crm/connectors/funnel-form.connector.ts
  • examples/market/connectors/exa-news-feed.connector.ts
  • examples/sales/connectors/salesforce-pipeline.connector.ts
  • packages/landing/astro.config.mjs
  • packages/landing/package.json
  • packages/landing/public/asciinema-player/asciinema-player.css
  • packages/landing/public/casts/claude.cast
  • packages/landing/scripts/gen-landing-snippets.ts
  • packages/landing/src/components/ArchitectureDiagram.tsx
  • packages/landing/src/components/ArchitectureSection.tsx
  • packages/landing/src/components/CodeBlock.tsx
  • packages/landing/src/components/FeatureBlock.tsx
  • packages/landing/src/components/FeatureGraphics.tsx
  • packages/landing/src/components/HeroProductCard.tsx
  • packages/landing/src/components/HeroSection.tsx
  • packages/landing/src/components/LandingPage.tsx
  • packages/landing/src/components/Nav.tsx
  • packages/landing/src/content/docs/getting-started/connector-sdk.md
  • packages/landing/src/content/docs/getting-started/reaction-sdk.md
  • packages/landing/src/content/docs/platforms/rest-api.md
  • packages/landing/src/content/docs/reference/connector-sdk.md
  • packages/landing/src/content/docs/reference/reaction-sdk.md
  • packages/landing/src/globals.css
  • packages/landing/src/layouts/BaseLayout.astro
  • packages/landing/src/pages/for/[useCase].astro
  • packages/landing/src/pages/index.astro
  • packages/landing/src/pages/reference/api-reference.astro
  • packages/landing/src/styles/theme-script.ts
  • skills/lobu/SKILL.md
💤 Files with no reviewable changes (4)
  • packages/landing/src/components/ArchitectureSection.tsx
  • packages/landing/src/components/HeroSection.tsx
  • packages/landing/src/components/FeatureBlock.tsx
  • packages/landing/src/components/FeatureGraphics.tsx

Comment thread examples/agent-community/connectors/discourse-posts.connector.ts
Comment on lines +14 to +16
const cursor = (ctx.checkpoint as any)?.last_post_id ?? 0;
const r = await fetch(`${ctx.config.base_url}/posts.json?before=${cursor + 50}`);
const posts: any[] = ((await r.json() as any).latest_posts ?? []).filter((p: any) => p.id > cursor).sort((a: any, b: any) => a.id - b.id);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

find . -name "discourse-posts.connector.ts" -type f

Repository: lobu-ai/lobu

Length of output: 123


🏁 Script executed:

cat -n ./examples/agent-community/connectors/discourse-posts.connector.ts

Repository: lobu-ai/lobu

Length of output: 1596


🏁 Script executed:

# Check if there are other files in the connector directory to understand the pattern
find ./examples/agent-community/connectors -type f -name "*.ts" | head -5

Repository: lobu-ai/lobu

Length of output: 123


🌐 Web query:

Discourse API posts.json before parameter pagination behavior

💡 Result:

In Discourse’s posts.json (the “list latest posts across topics” API), pagination is done with the query parameter before (a cursor), not with a page= offset. The docs say: “Load posts with an id lower than this value. Useful for pagination,” and the parameter table lists before for get/posts.json. [1] So the intended usage is: - Start with no before parameter (you get the most recent posts). - For the next page, send before= where is the last (oldest) post id you received, and Discourse returns posts with ids lower than that value. [1] If you instead try page=2 with /posts.json, you may find it doesn’t work; a Discourse Meta discussion notes you might need to use /latest.json?page=2 rather than /posts.json (because /posts.json isn’t the right endpoint for page-style pagination). [2] Example (conceptual): - First call: https:///posts.json - Next call: https:///posts.json?before=<oldest_post_id_from_previous_batch> That’s the “before” behavior for posts.json pagination in Discourse.

Citations:


🏁 Script executed:

# Check file context - is this an example or production code?
head -5 ./examples/agent-community/connectors/discourse-posts.connector.ts && \
# Check if there's a README or other docs explaining this
find ./examples/agent-community -name "*.md" -o -name "README*" | head -5

Repository: lobu-ai/lobu

Length of output: 481


Cursor window logic skips posts and auth key is unused.

Line 15 fetches posts with before=${cursor + 50}, and Line 16 filters to id > cursor. If more than 50 posts arrive between runs, those beyond the window are never read. Additionally, the api_key declared in the authSchema (line 9) is never used in the fetch request—add the API key to the request headers or query parameters.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/agent-community/connectors/discourse-posts.connector.ts` around
lines 14 - 16, The current cursor/window logic uses before=${cursor + 50} and
then filters id > cursor which can permanently skip posts if >50 new posts
arrive; replace that with a proper "since" style fetch and pagination: request
posts using after=${cursor} (or iterate fetching pages until no posts > cursor)
and remove the id>cursor post-filter, updating the checkpoint to the highest
returned post id (reference variables: cursor, ctx.checkpoint, the fetch call).
Also include the configured API key from your connector auth (use
ctx.secrets?.api_key or the authSchema key) in the request (e.g., add an Api-Key
header or query param when calling fetch against ctx.config.base_url) so
authentication is actually sent. Ensure to update the fetch invocation and
checkpoint handling in the same function accordingly.

Comment on lines +9 to +16
authSchema: { methods: [{ type: "env" as const, fields: [{ name: "access_token" }] }] },
feeds: { orders: { key: "orders", name: "Order updates" } },
};

async sync(ctx: SyncContext) {
const since = (ctx.checkpoint as any)?.updated_at_min ?? "2000-01-01T00:00:00Z";
const r = await fetch(`https://${ctx.config.shop}/admin/api/2024-10/orders.json?status=any&updated_at_min=${encodeURIComponent(since)}&limit=100`);
const orders: any[] = ((await r.json() as any).orders ?? []).sort((a: any, b: any) => new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime());
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

cat -n examples/delivery/connectors/shopify-orders.connector.ts

Repository: lobu-ai/lobu

Length of output: 1697


access_token is defined in authSchema but never used in the API call.

Line 9 declares env auth, but line 15 sends the Shopify Admin API request without the token, leaving sync unwired to its own auth contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/delivery/connectors/shopify-orders.connector.ts` around lines 9 -
16, The sync function is not using the access_token declared in authSchema;
update sync to read the token from ctx.auth or ctx.config (where auth is stored)
and include it as the Authorization header (Bearer <access_token>) or as
X-Shopify-Access-Token per Shopify API when performing fetch to orders.json;
modify the fetch call in sync to add the appropriate header and ensure it throws
or logs a clear error if access_token is missing, referencing authSchema and the
sync function so reviewers can find the change.

Comment thread examples/ecommerce/connectors/stripe-charges.connector.ts Outdated
Comment on lines +15 to +16
const r = await fetch(`https://api.stripe.com/v1/charges?limit=100&created[gt]=${cursor}`);
const data: any[] = ((await r.json() as any).data ?? []).sort((a: any, b: any) => a.created - b.created);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

cat -n examples/ecommerce/connectors/stripe-charges.connector.ts | head -40

Repository: lobu-ai/lobu

Length of output: 1642


Single-page sync with advancing checkpoint risks dropping charges.

The code fetches only one page of 100 records per sync (line 15), then advances the checkpoint to the timestamp of the last record in that page (line 25). If more than 100 charges exist between the previous checkpoint and the API response, the pagination will silently skip any records beyond the first 100 on the next sync. For example, if charges 1–100 are fetched and the newest has created=1100, the next sync will query created[gt]=1100, dropping charges 101–100 that were never fetched in the first request. This can cause financial records to be permanently dropped from the sync.

Either fetch all available records in a single sync by handling pagination, or use a more granular checkpoint strategy (e.g., offset-based or cursor-based pagination with explicit continuation handling).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/ecommerce/connectors/stripe-charges.connector.ts` around lines 15 -
16, The current single-page fetch using
fetch(`https://api.stripe.com/v1/charges?limit=100&created[gt]=${cursor}`) and
then advancing the checkpoint to the last returned record can drop records if
more than 100 charges exist; modify the connector to either (A) iterate
pagination until all pages are retrieved (use Stripe's next_page/has_more or the
response.data + starting_after/limit pattern) before sorting and advancing the
checkpoint, ensuring the loop references the same fetch call and the
response.data handling, or (B) switch the checkpoint to a cursor-based/offset
approach (store Stripe's starting_after/last_id or a composite timestamp+id)
instead of just the last record's created timestamp so no records are skipped
when updating the checkpoint. Ensure the code paths that read `cursor`, call
`fetch(...)`, and update the checkpoint (where the last record's created
timestamp is used) are updated accordingly.

Comment on lines +203 to +210
```
my-agent/
├── lobu.toml
├── connectors/
│ ├── funnel-form.connector.ts
│ └── stripe-charges.connector.ts
└── agents/my-agent/...
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the fenced tree block.

Line 203 opens a fenced block without a language, which triggers MD040 and can fail docs lint pipelines. Use text for this tree snippet.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 203-203: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/landing/src/content/docs/getting-started/connector-sdk.md` around
lines 203 - 210, The fenced code block that shows the project tree (the
triple-backtick block starting at the snippet with "my-agent/") is missing a
language tag and triggers MD040; update that block to use the text language tag
by changing the opening fence from ``` to ```text so the tree snippet is fenced
as plain text.

Comment on lines +100 to +109
```
my-agent/
├── lobu.toml
├── models/
│ ├── watchers/
│ │ └── account-health-monitor.yaml
│ └── reactions/
│ └── account-health-monitor.reaction.ts
└── agents/my-agent/...
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Specify a language for the filesystem snippet block.

Line 100 starts a fenced block without a language. Add text to satisfy markdownlint MD040.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 100-100: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/landing/src/content/docs/getting-started/reaction-sdk.md` around
lines 100 - 109, The fenced filesystem snippet starting at the code block should
specify a language to satisfy markdownlint MD040; update the opening fence from
``` to ```text so the block (showing the my-agent/ tree with lobu.toml, models/,
watchers/, reactions/, etc.) is explicitly marked as text.

Comment thread packages/landing/src/content/docs/platforms/rest-api.md Outdated
}
```

Connectors declaring this method must implement `authenticate(ctx)` and stream [`AuthArtifact`s](#authartifact).
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix broken in-page fragment link for AuthArtifact.

Line 180 links to #authartifact, but the section is a combined heading, so this fragment is invalid (MD051). Point to the actual generated anchor (or split out a dedicated ### AuthArtifact heading and keep #authartifact).

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 180-180: Link fragments should be valid

(MD051, link-fragments)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/landing/src/content/docs/reference/connector-sdk.md` at line 180,
The in-page fragment link `#authartifact` in the sentence referencing
`AuthArtifact` is invalid because the actual section is a combined heading;
update the documentation so the fragment resolves: either add a dedicated
heading `### AuthArtifact` (so the `#authartifact` anchor becomes valid) or
change the link target to the exact generated anchor for the combined heading
(replace `#authartifact` with the correct anchor text). Ensure the sentence
still mentions `authenticate(ctx)` and streams `AuthArtifact`s and that the link
points to the newly created `AuthArtifact` heading or the correct
combined-heading anchor.

Comment thread skills/lobu/SKILL.md
1. **What is the agent for?** One sentence. (Example: "Triage support emails and draft replies for the on-call engineer.")
2. **Who uses it?** Just you, your team, or each of your customers (multi-tenant)?
3. **What does it need to remember?** Translate the answer into 1–3 entity types. (Example: "support tickets, customers, recurring issues.")
4. **Where does the data come from?** One source to start. (Slack, Gmail, GitHub, Linear, Stripe, a custom webhook, a CSV — pick one.) If the user names a source Lobu does not ship a bundled connector for, plan to write a custom `connector.ts`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the canonical connector filename pattern in onboarding text.

Line 34 says connector.ts, but this guide later standardizes on connectors/<name>.connector.ts (Line 52). Align Line 34 to the same pattern to avoid scaffolding mistakes.

🧰 Tools
🪛 LanguageTool

[style] ~34-~34: It’s more common nowadays to write this noun as one word.
Context: ...stom webhook, a CSV — pick one.) If the user names a source Lobu does not ship a bundled c...

(RECOMMENDED_COMPOUNDS)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/lobu/SKILL.md` at line 34, Update the onboarding text that currently
references "connector.ts" to use the canonical pattern
"connectors/<name>.connector.ts" so it matches the rest of the guide; replace
the occurrence of connector.ts in the SKILL.md sentence with
connectors/<name>.connector.ts and ensure wording remains consistent with the
later reference to connectors/<name>.connector.ts.

@buremba
Copy link
Copy Markdown
Member Author

buremba commented May 20, 2026

  • examples/ecommerce/connectors/stripe-charges.connector.ts:9-24 is pinned as the canonical “real” connector example, but it doesn’t match the SDK contract: auth uses type: "env" / name instead of env_keys / key, emitted events omit required payload_text, and the Stripe secret is never sent in an Authorization header. Because this exact file is surfaced in landing-snippets.json and linked as the full example, copy-paste users get an unauthenticated/non-compiling connector.
  • packages/landing/src/content/docs/getting-started/connector-sdk.md:77-96 declares env_keys auth but reads the PAT from ctx.credentials?.accessToken. In the current runtime, ctx.credentials is OAuth-only; env-key credentials are merged into the sync config/env path. This makes the SDK guide’s “typed connector, end to end” silently send an empty bearer token.
  • The rewrite presents @lobu/reaction-sdk as a package/surface in prominent places (ArchitectureDiagram.tsx:242, sidebar/API quicklinks/reference title), but there is no @lobu/reaction-sdk package/export — the types come from @lobu/connector-sdk. The reference page eventually says this, but the landing/nav labels will still lead devs to try installing/importing a fake package.
  • Hero accessibility regression: HeroAsciinema mounts a 42s terminal cast into an otherwise empty <div> with no accessible name, transcript, or fallback summary (LandingPage.tsx:359-421). If the player fails or for screen-reader users, the primary demo content is unavailable.
  • Real-looking fake data should be labeled or skeletonized: the architecture table hardcodes acme corp, jane doe, q3 review (ArchitectureDiagram.tsx:371-374), and the run-anywhere terminal hardcodes pid=72341, acme, us-east-1, acme.lobu.run (LandingPage.tsx:920-1003) without saying it is example output.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
packages/landing/src/content/docs/getting-started/reaction-sdk.md (1)

124-133: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Specify a language for the tree code block.

Line 124 starts a fenced block without a language tag. Please change it to ```text to resolve MD040.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/landing/src/content/docs/getting-started/reaction-sdk.md` around
lines 124 - 133, The fenced code block that shows the directory tree (the block
beginning with "my-agent/" in reaction-sdk.md) is missing a language tag; update
the opening fence from ``` to ```text so the tree is marked as plain text and
resolves MD040 (look for the code block containing "lobu.toml" and the
models/reactions/watchers entries).
packages/landing/src/content/docs/getting-started/connector-sdk.md (1)

305-312: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the filesystem tree fence.

Line 305 opens a fenced block without a language. Use text (i.e., ```text) to satisfy MD040 and keep docs lint clean.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/landing/src/content/docs/getting-started/connector-sdk.md` around
lines 305 - 312, The fenced code block showing the filesystem tree starting with
"my-agent/" uses an unlabeled triple-backtick; change its opening fence from ```
to ```text so the block becomes a text-labeled fence (e.g., ```text) to satisfy
MD040 and keep the docs lint clean; update the fence that encloses the tree (the
block that contains "my-agent/ ├── lobu.toml ...") accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@packages/landing/src/content/docs/getting-started/connector-sdk.md`:
- Around line 305-312: The fenced code block showing the filesystem tree
starting with "my-agent/" uses an unlabeled triple-backtick; change its opening
fence from ``` to ```text so the block becomes a text-labeled fence (e.g.,
```text) to satisfy MD040 and keep the docs lint clean; update the fence that
encloses the tree (the block that contains "my-agent/ ├── lobu.toml ...")
accordingly.

In `@packages/landing/src/content/docs/getting-started/reaction-sdk.md`:
- Around line 124-133: The fenced code block that shows the directory tree (the
block beginning with "my-agent/" in reaction-sdk.md) is missing a language tag;
update the opening fence from ``` to ```text so the tree is marked as plain text
and resolves MD040 (look for the code block containing "lobu.toml" and the
models/reactions/watchers entries).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 75898b1c-2e10-4440-86bf-9cc7914a7016

📥 Commits

Reviewing files that changed from the base of the PR and between 008f05d and 79d450b.

📒 Files selected for processing (3)
  • packages/landing/src/content/docs/getting-started/connector-sdk.md
  • packages/landing/src/content/docs/getting-started/reaction-sdk.md
  • packages/landing/src/content/docs/reference/reaction-sdk.md
✅ Files skipped from review due to trivial changes (1)
  • packages/landing/src/content/docs/reference/reaction-sdk.md

buremba added 5 commits May 20, 2026 01:17
…k contract

- auth: type 'env' -> 'env_keys', field 'name' -> 'key', add label/secret/required
- read secret key from ctx.config.secret_key (env_keys land in ctx.config)
- send Authorization: Bearer header so the call actually authenticates
- emit required payload_text on every EventEnvelope
- replace any-casts with typed Checkpoint + StripeCharge + EventEnvelope[]

Regenerated landing-snippets.json from the fixed source so the landing
page code panel ships the working version.
Per the runtime (packages/connector-worker/src/executor/child-runner.ts),
env_keys values land in `ctx.config` under the field's `key`, not on
`ctx.credentials`. `ctx.credentials` is OAuth-only.

- getting-started/connector-sdk.md: read PAT from ctx.config.token; clarify
  the SyncContext table and the inline auth-models note; apply the same fix
  to the assign_issue execute() example.
- reference/connector-sdk.md: add an explicit 'where credentials land'
  paragraph after SyncContext mapping each auth method to the right slot.
There is no @lobu/reaction-sdk npm package — reactions are part of
@lobu/connector-sdk. Keep reactions as a first-class concept (own docs
page, sidebar entry, arch pill) but drop language that implies a
separate package.

- ArchitectureDiagram: pill label 'reactions' (was '@lobu/reaction-sdk')
  with caption 'from @lobu/connector-sdk'.
- astro.config.mjs: sidebar labels 'Reaction SDK' / '@lobu/reaction-sdk'
  -> 'Reactions'. URL slugs unchanged.
- reference/api-reference.astro: quick-link 'Reactions' (was
  '@lobu/reaction-sdk').
- getting-started/reaction-sdk.md: title 'Reactions'; open with the
  explicit 'part of @lobu/connector-sdk' framing.
- reference/reaction-sdk.md: title 'Reactions'; clarify all types come
  from @lobu/connector-sdk.
- platforms/rest-api.md + connector-sdk guide/reference cross-links:
  relabel 'Reactions' with parenthetical 'part of @lobu/connector-sdk'.
The hero terminal cast was mounted into an empty div with no role,
no label, no fallback text. Screen-reader users and JS-disabled
visitors got nothing.

- Wrap the player in role='img' + aria-label describing the demo.
- Add a sr-only <p> sibling summarising what the asciicast contains,
  so assistive tech and no-JS visitors still get the gist even when
  the asciinema-player script fails to mount (JS error, blocked CDN).
- Split the wrapper / mount-target so the player's DOM rewrites don't
  clobber the sr-only summary.
Visitors could read the entities-table widget and run-anywhere terminal
cards as a snapshot of a real customer's data.

- ArchitectureDiagram entities table: 'acme corp' / 'jane doe' /
  'q3 review' -> 'Customer A/B/C'. Reads as a schema preview.
- LandingPage Run-anywhere local card: pid=72341 / 2 entities /
  1 armed -> pid=<n> / N entities / N armed.
- LandingPage Run-anywhere cloud card: org=acme / region=us-east-1 /
  1 deployed / acme.lobu.run -> org=<your-org> / region=<your-region>
  / N deployed / <your-org>.lobu.run.

Biome reformatted nesting inside HeroAsciinema after the prior commit
nested the player <div>; carried that whitespace-only change in this
commit.
@buremba
Copy link
Copy Markdown
Member Author

buremba commented May 20, 2026

previous findings resolved — looks clean to merge

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (4)
examples/ecommerce/connectors/stripe-charges.connector.ts (1)

20-33: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Paginate Stripe results before checkpoint advancement to avoid dropped events.

Line 20 fetches only one page (limit=100), while Line 33 advances the checkpoint to the newest created in that page. If >100 charges exist between runs (or multiple charges share the boundary timestamp), some events can be skipped permanently.

Use has_more + starting_after paging and advance a composite checkpoint (timestamp + stable tie-breaker id) after all pages are processed.

Stripe Charges List API pagination semantics: confirm `has_more`, `starting_after`, and ordering guarantees when using `created[gt]` filters.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/ecommerce/connectors/stripe-charges.connector.ts` around lines 20 -
33, The current fetch in stripe-charges.connector.ts only retrieves one page and
advances the checkpoint to the newest created in that page (using
data.at(-1)?.created), which can drop events; change the logic in the connector
that builds events (the fetch/const r, parsing into data, events mapping, and
return checkpoint) to loop with Stripe pagination (inspect response.has_more and
use starting_after with the last charge.id) accumulating all pages into a single
data/events array before returning, and return a composite checkpoint object
(e.g., { last_created: <timestamp>, last_id: <stable_charge_id> } ) so ties at
the same timestamp are resolved deterministically when advancing the checkpoint.
Ensure you use the charge.id as the stable tie-breaker and only advance the
checkpoint after all pages are processed.
packages/landing/src/content/docs/getting-started/reaction-sdk.md (1)

124-124: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Specify a language for the project-tree fenced block.

Line 124 starts a fenced block without a language (MD040).

Suggested fix
-```
+```text
 my-agent/
 ├── lobu.toml
 ├── models/
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/landing/src/content/docs/getting-started/reaction-sdk.md` at line
124, The fenced code block that begins with ``` is missing a language label
(MD040); update the fence used for the project-tree snippet to include a
language identifier (e.g., change the opening fence from ``` to ```text) so the
block is explicitly marked as plain text for the project-tree content in
reaction-sdk.md.
packages/landing/src/content/docs/getting-started/connector-sdk.md (1)

310-310: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the filesystem tree code fence.

The fence opened at Line 310 is missing a language identifier (MD040).

Suggested fix
-```
+```text
 my-agent/
 ├── lobu.toml
 ├── connectors/
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/landing/src/content/docs/getting-started/connector-sdk.md` at line
310, The code fence that renders the filesystem tree (the opening
triple-backtick immediately before the "my-agent/" tree block) is missing a
language tag; update the opening fence from ``` to ```text so the block is
explicitly marked as plain text (look for the fence preceding the "my-agent/" /
connectors/ tree in connector-sdk.md and change the fence to ```text).
packages/landing/src/content/docs/reference/connector-sdk.md (1)

180-180: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix invalid in-page fragment link for AuthArtifact.

Line 180 links to #authartifact, but that anchor does not exist for the combined heading (MD051).

Suggested fix
-Connectors declaring this method must implement `authenticate(ctx)` and stream [`AuthArtifact`s](`#authartifact`).
+Connectors declaring this method must implement `authenticate(ctx)` and stream [`AuthArtifact`s](`#authcontext--authartifact--authresult`).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/landing/src/content/docs/reference/connector-sdk.md` at line 180,
The in-page link to AuthArtifact is using an invalid anchor `#authartifact`;
update the link in the sentence that mentions "stream
[`AuthArtifact`s](`#authartifact`)" to use the correct generated heading anchor
for the "AuthArtifact" heading (replace `#authartifact` with the proper anchor,
e.g. `#auth-artifact`), ensuring the link matches the combined heading slug for
the AuthArtifact section and verifies it resolves in the rendered doc; keep the
surrounding text and the reference to authenticate(ctx) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@examples/ecommerce/connectors/stripe-charges.connector.ts`:
- Around line 20-33: The current fetch in stripe-charges.connector.ts only
retrieves one page and advances the checkpoint to the newest created in that
page (using data.at(-1)?.created), which can drop events; change the logic in
the connector that builds events (the fetch/const r, parsing into data, events
mapping, and return checkpoint) to loop with Stripe pagination (inspect
response.has_more and use starting_after with the last charge.id) accumulating
all pages into a single data/events array before returning, and return a
composite checkpoint object (e.g., { last_created: <timestamp>, last_id:
<stable_charge_id> } ) so ties at the same timestamp are resolved
deterministically when advancing the checkpoint. Ensure you use the charge.id as
the stable tie-breaker and only advance the checkpoint after all pages are
processed.

In `@packages/landing/src/content/docs/getting-started/connector-sdk.md`:
- Line 310: The code fence that renders the filesystem tree (the opening
triple-backtick immediately before the "my-agent/" tree block) is missing a
language tag; update the opening fence from ``` to ```text so the block is
explicitly marked as plain text (look for the fence preceding the "my-agent/" /
connectors/ tree in connector-sdk.md and change the fence to ```text).

In `@packages/landing/src/content/docs/getting-started/reaction-sdk.md`:
- Line 124: The fenced code block that begins with ``` is missing a language
label (MD040); update the fence used for the project-tree snippet to include a
language identifier (e.g., change the opening fence from ``` to ```text) so the
block is explicitly marked as plain text for the project-tree content in
reaction-sdk.md.

In `@packages/landing/src/content/docs/reference/connector-sdk.md`:
- Line 180: The in-page link to AuthArtifact is using an invalid anchor
`#authartifact`; update the link in the sentence that mentions "stream
[`AuthArtifact`s](`#authartifact`)" to use the correct generated heading anchor
for the "AuthArtifact" heading (replace `#authartifact` with the proper anchor,
e.g. `#auth-artifact`), ensuring the link matches the combined heading slug for
the AuthArtifact section and verifies it resolves in the rendered doc; keep the
surrounding text and the reference to authenticate(ctx) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 134d6fa6-d855-45d4-93c2-8bc324f9f4f8

📥 Commits

Reviewing files that changed from the base of the PR and between 79d450b and 6f9f3d1.

⛔ Files ignored due to path filters (1)
  • packages/landing/src/generated/landing-snippets.json is excluded by !**/generated/**
📒 Files selected for processing (10)
  • examples/ecommerce/connectors/stripe-charges.connector.ts
  • packages/landing/astro.config.mjs
  • packages/landing/src/components/ArchitectureDiagram.tsx
  • packages/landing/src/components/LandingPage.tsx
  • packages/landing/src/content/docs/getting-started/connector-sdk.md
  • packages/landing/src/content/docs/getting-started/reaction-sdk.md
  • packages/landing/src/content/docs/platforms/rest-api.md
  • packages/landing/src/content/docs/reference/connector-sdk.md
  • packages/landing/src/content/docs/reference/reaction-sdk.md
  • packages/landing/src/pages/reference/api-reference.astro
✅ Files skipped from review due to trivial changes (1)
  • packages/landing/src/content/docs/reference/reaction-sdk.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/landing/src/content/docs/platforms/rest-api.md
  • packages/landing/src/pages/reference/api-reference.astro
  • packages/landing/astro.config.mjs
  • packages/landing/src/components/LandingPage.tsx

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