Skip to content

feat(landing): per-use-case snippet tabs, connector logo wall, drop asciinema, simplify nav#988

Merged
buremba merged 8 commits into
mainfrom
feat/landing-h1
May 20, 2026
Merged

feat(landing): per-use-case snippet tabs, connector logo wall, drop asciinema, simplify nav#988
buremba merged 8 commits into
mainfrom
feat/landing-h1

Conversation

@buremba
Copy link
Copy Markdown
Member

@buremba buremba commented May 20, 2026

Dev-focused landing rework.

Highlights

  • Per-use-case snippet tabs — a "See it for your use case" strip swaps the connector / memory-schema / watcher code snippets per vertical (legal, finance, sales, leadership, market, agent-community). Generated from real example projects via `gen-landing-snippets`; `/for/` pages land on the matching tab. Connector shows the full `*.connector.ts` (complete TypeScript).
  • Connector logo wall — `gen-connectors.ts` pulls all built-in connectors + their brand logos from `simple-icons` at build time (no hardcoded paths); each chip links to its source file.
  • Architecture diagram reworked: heading "Events in. Entities out. Agents on top." (centered), `LLM watcher` derivation label, `EXTERNAL SERVICES → reactions`, clearer footers, three equal Connectors input blocks. Per-domain egress-judge form in the deliveroo example (SKILL.md + lobu.toml).
  • Removed asciinema — deleted the vendored player + casts (~512 KB) and the fragile WASM-worker hero; the hero ends on the CTAs (video can slot in later).
  • Nav — dropped the Solutions mega-menu; promoted Docs to a top-level link. Footer keeps the use-case links (SEO).
  • Cleanup — removed dead `/memory` + `/skills` redirect stubs; added `#memory`/`#skills` section anchors so footer links resolve. Swept em dashes from marketing copy (house rule added to AGENTS.md).

Validation

  • `bun run build` passes (83 pages).
  • Per-case differentiation verified (legal vs sales diff > 0 on connector/watcher snippets).
  • Rebased clean onto main; frozen lockfile consistent.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Per-use-case landing variants with connector/memory/watcher snippets
    • Improved connector discovery and brand icon generation
    • Landing hero simplified (removed embedded demo) and setup prompt streamlined
  • Bug Fixes

    • Reconciliation monitoring now aggregates related alerts into a single alert
  • Documentation

    • Added lobu‑crm reference example
    • Updated skill network policy docs
  • Style

    • Redesigned architecture diagram; site copy punctuation/wording updated
    • Removed Solutions menu; providers table shows "N/A" for missing metadata
    • Asciinema player assets/demo removed

buremba added 7 commits May 20, 2026 22:27
…ilding knowledge graph'

Verb-led headline with stronger actionability. Adds article 'a' for
cleaner grammar. Keeps 'proactive' to differentiate from passive memory
stores (memory.store) and preserves 'self-building knowledge graph' as
the technical moat. Updates SEO title, meta description, and JSON-LD.
ConnectorRuntime<C, F> now carries checkpoint and config type params.
Defaults to Record<string, unknown> so existing connectors compile unchanged.

New connectors get typed ctx.checkpoint and ctx.config — no more casts:
  class MyConnector extends ConnectorRuntime<MyCheckpoint, MyConfig> {
    async sync(ctx: SyncContext<MyCheckpoint, MyConfig>) {
      const lastSync = ctx.checkpoint?.last_sync_at;  // typed!
      const label = ctx.config.label;                  // typed!
    }
  }

Migrates google_gmail as reference.
Minimal, well-commented example showing the full flow:
  schema.yaml → watcher (cron + extraction_schema) → reaction script

Each file has inline docs explaining the structure. Use as a template
for new projects.
Adds ReactionClient interface mirroring the actual isolated-vm proxy
surface (knowledge.save/search/read/delete, entities CRUD, query, log).
Reaction scripts now get full editor autocomplete:

  import type { ReactionClient, ReactionContext } from '@lobu/connector-sdk';
  export default async (ctx: ReactionContext, client: ReactionClient) => {
    await client.knowledge.save({ content: '...', semantic_type: 'digest' });
  };

Updates starter, lobu-crm, sales, and finance reaction examples to use
ReactionClient instead of `any`.
The starter example didn't run end-to-end — no connectors, no real data
flow. Better to have one real example with great docs than a fake one.

- Deletes examples/starter/ (was just a stripped-down stub)
- Updates lobu-crm/funnel-form.connector.ts to use generic ConnectorRuntime
- Adds lobu-crm/README.md explaining the structure and key files
- Existing reaction scripts already use ReactionClient from prior commit
Sections now pull from different examples to show diversity:
  Connectors: ecommerce/stripe-charges (unchanged)
  Memory:     sales/schema.yaml (unchanged)
  Watchers:   leadership/board-action-tracker (was sales/account-health)
  Reactions:  finance/reconciliation-monitor (was sales/account-health)
  Agents:     lobu-crm/lobu.toml (was sales)
  Skills:     office-bot/deliveroo-order (unchanged)

Connectors section: added dotted-underline links to GitHub, Linear,
Slack, Telegram, Discord, WhatsApp, X doc pages.

Agents section: chat surface names (Slack, Telegram, Discord, Teams,
WhatsApp) now link to their channel docs.

Watchers section: added separate links for watchers guide and reaction
SDK docs.
- per-use-case connector/watcher/memory snippets via tab strip (gen-connectors + simple-icons logo wall)
- architecture diagram: Events in/Entities out/Agents on top, per-domain egress judge example
- remove asciinema player + casts; em-dash sweep across marketing copy
- nav: drop Solutions menu, promote Docs to top level
- remove dead /memory /skills stubs, add #memory/#skills section anchors
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4050ae30-8edf-4845-916d-32c3981e1f8d

📥 Commits

Reviewing files that changed from the base of the PR and between 7b69f17 and 419dc66.

📒 Files selected for processing (5)
  • packages/connector-sdk/src/reaction-client-types.ts
  • packages/landing/astro.config.mjs
  • packages/landing/src/components/LandingPage.tsx
  • packages/landing/src/content/docs/guides/sync-from-github.md
  • packages/landing/src/pages/for/[useCase].astro

📝 Walkthrough

Walkthrough

Adds generics to the connector SDK, introduces a typed ReactionClient API, updates example connectors/reactions to use types, implements per-use-case landing snippet generation and UI wiring, removes the asciinema demo, and normalizes landing copy punctuation (no em-dashes).

Changes

Connector SDK Type Generics

Layer / File(s) Summary
SyncContext and SyncResult generic contracts
packages/connector-sdk/src/connector-types.ts
SyncContext and SyncResult gain type parameters for checkpoint (C) and feed config (F), replacing fixed Record<string, unknown> types.
ConnectorRuntime generic base class
packages/connector-sdk/src/connector-runtime.ts
ConnectorRuntime becomes generic <C,F>; sync is retyped to sync(ctx: SyncContext<C, F>): Promise<SyncResult<C>>.
Connector implementations adopt generics
packages/connectors/src/google_gmail.ts, examples/lobu-crm/connectors/funnel-form.connector.ts
Connectors are parameterized with checkpoint/config generics and remove unsafe casts.
SDK public type exports
packages/connector-sdk/src/index.ts
Re-exports ReactionClient and related input/filter/search types.

Reaction Client Type System

Layer / File(s) Summary
ReactionClient and input type definitions
packages/connector-sdk/src/reaction-client-types.ts
New interfaces define ReactionClient and typed inputs for knowledge and entity operations.
Example reactions typed with ReactionClient
examples/finance/models/reactions/reconciliation-monitor.reaction.ts, examples/lobu-crm/models/reactions/inbound-triage.reaction.ts, examples/sales/models/reactions/account-health-monitor.reaction.ts
Reaction functions now accept client: ReactionClient; reconciliation-monitor refactors input shape and persists an aggregated alert.

Landing Page Use-Case Redesign

Layer / File(s) Summary
Connector and landing snippet generation
packages/landing/scripts/gen-connectors.ts, packages/landing/scripts/gen-landing-snippets.ts, packages/landing/package.json
Add connector extractor, per-use-case snippet manifest generation, and add simple-icons dependency; include generation steps in predev/prebuild.
LandingPage state and snippet wiring
packages/landing/src/components/LandingPage.tsx
Add defaultUseCaseId/active use-case state, render UseCaseTabs, wire per-use-case connector/memory/watcher snippets into sections, and remove asciinema demo.
Product sections parameterized with snippet props
packages/landing/src/components/LandingPage.tsx
ConnectorsSection/MemorySection/WatchersSection accept snippet and slug props and render selected examples.
Layout, navigation, and page routing
packages/landing/src/layouts/BaseLayout.astro, packages/landing/src/components/Nav.tsx, packages/landing/src/pages/index.astro, packages/landing/src/pages/for/[useCase].astro, packages/landing/src/pages/memory.astro, packages/landing/src/pages/skills.astro
Remove asciinema asset injection and prop, add standalone Docs link, stop passing heroCopy, and delete redirect pages for memory/skills.
Architecture diagram visual updates
packages/landing/src/components/ArchitectureDiagram.tsx
Header centered, connector logo wall replaced by SourceRow list, agent channels become links, add External services row, relabel derivation arrow.

Text and Punctuation Normalization

Layer / File(s) Summary
Landing component and script comments/strings
packages/landing/src/components/CodeBlock.tsx, packages/landing/src/components/SampleChat.tsx, packages/landing/src/components/ProvidersRegistryTable.tsx
Tokenizer comments and JSDoc updated (em-dashes → colons); provider-metadata defaults changed from "—" to "N/A".
Hero and product section descriptive copy
packages/landing/src/components/LandingPage.tsx
Hero, feature lists, and section descriptions rephrased to remove em-dashes and adjust punctuation.
Chat scenarios and client config copy
packages/landing/src/chat-scenarios.ts, packages/landing/src/connect-from-config.ts
Chat scenario messages and connect-from valueProp strings updated to avoid em-dashes.
Use-case showcase runtime and chat content
packages/landing/src/use-case-showcases.ts
Multiple runtime journey and chat scenario responses reworded for punctuation/clarity.
Layout and theme metadata comments
packages/landing/src/layouts/BaseLayout.astro, packages/landing/src/styles/theme-tokens.ts, packages/landing/src/pages/reference/api-reference.astro, packages/landing/src/pages/serverless-openclaw.astro, packages/landing/src/components/connect-from/TryItSection.tsx
Metadata comments and default descriptions rephrased; asciinema injection removed.

Example Projects and Agent Documentation

Layer / File(s) Summary
AGENTS.md rule and example documentation
AGENTS.md, examples/lobu-crm/README.md
Add rule forbidding em-dashes in landing copy; add lobu-crm README documenting example structure.
Office bot skill and config policy updates
examples/office-bot/agents/food-ordering/skills/deliveroo-order/SKILL.md, examples/office-bot/lobu.toml
Deliveroo domains remapped to a dedicated deliveroo judge and judges block key renamed accordingly.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • lobu-ai/lobu#988: Overlaps landing rework, connector/reactor typing, and AGENTS.md rule additions.
  • lobu-ai/lobu#941: Related AGENTS.md/documentation changes that may overlap.
  • lobu-ai/lobu#737: Landing UI updates touching LandingPage and product sections.

Suggested reviewers

  • codex-approver

"I nibble at the changes with a hop and cheer,
Generics and snippets now appear!
No em-dashes in sight, just commas clear,
Reactions tidy, connectors typed—hip-hip hooray, dear!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.21% 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 clearly summarizes the main changes: per-use-case snippet tabs, connector logo wall, asciinema removal, and nav simplification.
Description check ✅ Passed The description provides a comprehensive summary with highlights, validation details, and context, though it lacks explicit test plan checkboxes.
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-h1

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!

@buremba
Copy link
Copy Markdown
Member Author

buremba commented May 20, 2026

bug_free 82, simplicity 78, slop 12, bugs 1, 0 blockers

Script-run typecheck/unit/integration all passed. Exploratory: cd packages/landing && bun run build passed; Astro emitted only the existing CSS @import warning. No server boot, diff is landing/examples/SDK type surface.

Suggested fixes

File Line Change
packages/connector-sdk/src/reaction-client-types.ts 96 Change knowledge.save() to return the actual saveContent shape (id/entity_ids/title/semantic_type/created_at/optional supersedes_event_id/view_url) or Promise; event_id is not returned by the runtime.
packages/landing/src/components/LandingPage.tsx 59 Remove the unused linkTabsToCampaigns prop, and remove the corresponding prop passed from packages/landing/src/pages/for/[useCase].astro unless tab navigation is implemented.
Full verdict JSON
{
  "bug_free_confidence": 82,
  "bugs": 1,
  "slop": 12,
  "simplicity": 78,
  "blockers": [],
  "change_type": "feat",
  "behavior_change_risk": "low",
  "tests_adequate": true,
  "suggested_fixes": [
    {
      "file": "packages/connector-sdk/src/reaction-client-types.ts",
      "line": 96,
      "change": "Change knowledge.save() to return the actual saveContent shape (id/entity_ids/title/semantic_type/created_at/optional supersedes_event_id/view_url) or Promise<unknown>; event_id is not returned by the runtime."
    },
    {
      "file": "packages/landing/src/components/LandingPage.tsx",
      "line": 59,
      "change": "Remove the unused linkTabsToCampaigns prop, and remove the corresponding prop passed from packages/landing/src/pages/for/[useCase].astro unless tab navigation is implemented."
    }
  ],
  "notes": "Script-run typecheck/unit/integration all passed. Exploratory: cd packages/landing && bun run build passed; Astro emitted only the existing CSS @import warning. No server boot, diff is landing/examples/SDK type surface.",
  "categories": {
    "src": 1495,
    "tests": 0,
    "docs": 52,
    "config": 9,
    "deps": 16,
    "migrations": 0,
    "ci": 0,
    "generated": 1597
  }
}

Local review gate — branch protection can require the pi-review commit status. See docs/REVIEW_SCHEMA.md.

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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/landing/scripts/gen-landing-snippets.ts (1)

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

Scope block-scalar shortening to judge policies only.

Lines 565-590 currently rewrite any <key>: > / <key>: | scalar, which can unintentionally clobber unrelated frontmatter fields if they use block scalars. Restrict this transform to the network.judges subtree.

🤖 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 562 - 590, The
block-scalar shortening currently matches any "<key>: >|"-style scalar via the
blockScalar regex (in the block starting with const blockScalar = ...), which
can clobber unrelated frontmatter; change the guard so this transform only runs
when the current YAML path is inside network.judges. To fix: before applying the
rewrite (before using baseIndent/policyName and pushing the folded text), walk
upward from the current line i to collect ancestor mapping keys by finding
previous non-empty lines with lesser indentation and extracting their keys (use
the same key-extraction logic as blockScalar to get a parentKey), build the
ancestor path (e.g., "network.judges" if the immediate parent is judges and its
parent is network), and only perform the blockScalar rewrite when the built path
endsWith "network.judges" (otherwise skip and leave i unchanged). Keep existing
symbols: blockScalar, baseIndent, policyName, childPad, and i/j logic; just add
the ancestor-path check before mutating out and advancing i.
🤖 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/finance/models/reactions/reconciliation-monitor.reaction.ts`:
- Around line 22-25: The issue: windows with only payment_risks are ignored;
update the detection and alert payload to include payment_risks. Modify the
boolean computation in hasIssues (the expression that references
data.unreconciled_count, data.new_variances, data.approaching_deadlines) to also
check (data.payment_risks?.length ?? 0) > 0, and ensure the saved alert
body/metadata (the object constructed where the alert payload is built further
down in the reaction) includes payment_risks so risk-only windows are captured
and persisted; update the analogous checks at the other occurrences mentioned
(the blocks around lines where hasIssues is evaluated and where the alert
body/metadata are assembled).

In `@examples/lobu-crm/README.md`:
- Around line 8-28: The fenced code block in the README.md directory listing is
missing a language specifier; update the opening triple backticks for the block
that begins with "lobu-crm/" to include a language identifier such as text or
plaintext (e.g., change ``` to ```text) so the directory tree renders correctly;
locate the block in examples/lobu-crm/README.md and modify the opening fence
accordingly.

In `@packages/landing/scripts/gen-landing-snippets.ts`:
- Around line 672-678: The findConnectorFile function currently picks the first
file matching *.connector.ts which can be nondeterministic; instead read all
matches using readdirSync(connectorsDir).filter(f =>
f.endsWith(".connector.ts")), then if the resulting array length !== 1 throw a
clear Error (include connectorsDir and the list or count) to fail fast; when
exactly one match exists, return the same { abs, rel } values as before using
that single filename.

In `@packages/landing/src/chat-scenarios.ts`:
- Line 108: The bot copy for the settings link in
packages/landing/src/chat-scenarios.ts is a broken sentence; update the object
property text (the "text" value used for the settings-link) to a single clear
sentence such as: "You can change the model from Settings — this opens a scoped
page with your current agent configuration." Replace the existing malformed
string with this corrected sentence so the in-chat message reads clearly.

---

Outside diff comments:
In `@packages/landing/scripts/gen-landing-snippets.ts`:
- Around line 562-590: The block-scalar shortening currently matches any "<key>:
>|"-style scalar via the blockScalar regex (in the block starting with const
blockScalar = ...), which can clobber unrelated frontmatter; change the guard so
this transform only runs when the current YAML path is inside network.judges. To
fix: before applying the rewrite (before using baseIndent/policyName and pushing
the folded text), walk upward from the current line i to collect ancestor
mapping keys by finding previous non-empty lines with lesser indentation and
extracting their keys (use the same key-extraction logic as blockScalar to get a
parentKey), build the ancestor path (e.g., "network.judges" if the immediate
parent is judges and its parent is network), and only perform the blockScalar
rewrite when the built path endsWith "network.judges" (otherwise skip and leave
i unchanged). Keep existing symbols: blockScalar, baseIndent, policyName,
childPad, and i/j logic; just add the ancestor-path check before mutating out
and advancing i.
🪄 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: 23ebe8fd-c36a-4555-a06d-19fea4ec0f06

📥 Commits

Reviewing files that changed from the base of the PR and between 4832bf2 and 7b69f17.

⛔ Files ignored due to path filters (7)
  • bun.lock is excluded by !**/*.lock
  • 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/connectors.json is excluded by !**/generated/**
  • packages/landing/src/generated/landing-snippets.json is excluded by !**/generated/**
  • packages/landing/src/generated/use-case-models.ts is excluded by !**/generated/**
📒 Files selected for processing (37)
  • AGENTS.md
  • examples/finance/models/reactions/reconciliation-monitor.reaction.ts
  • examples/lobu-crm/README.md
  • examples/lobu-crm/connectors/funnel-form.connector.ts
  • examples/lobu-crm/models/reactions/inbound-triage.reaction.ts
  • examples/office-bot/agents/food-ordering/skills/deliveroo-order/SKILL.md
  • examples/office-bot/lobu.toml
  • examples/sales/models/reactions/account-health-monitor.reaction.ts
  • packages/connector-sdk/src/connector-runtime.ts
  • packages/connector-sdk/src/connector-types.ts
  • packages/connector-sdk/src/index.ts
  • packages/connector-sdk/src/reaction-client-types.ts
  • packages/connectors/src/google_gmail.ts
  • packages/landing/package.json
  • packages/landing/public/asciinema-player/asciinema-player.css
  • packages/landing/public/casts/claude.cast
  • packages/landing/scripts/gen-connectors.ts
  • packages/landing/scripts/gen-landing-snippets.ts
  • packages/landing/src/chat-scenarios.ts
  • packages/landing/src/components/ArchitectureDiagram.tsx
  • packages/landing/src/components/CodeBlock.tsx
  • packages/landing/src/components/LandingPage.tsx
  • packages/landing/src/components/Nav.tsx
  • packages/landing/src/components/ProvidersRegistryTable.tsx
  • packages/landing/src/components/SampleChat.tsx
  • packages/landing/src/components/ServerlessSection.tsx
  • packages/landing/src/components/connect-from/TryItSection.tsx
  • packages/landing/src/connect-from-config.ts
  • packages/landing/src/layouts/BaseLayout.astro
  • packages/landing/src/pages/for/[useCase].astro
  • packages/landing/src/pages/index.astro
  • packages/landing/src/pages/memory.astro
  • packages/landing/src/pages/reference/api-reference.astro
  • packages/landing/src/pages/serverless-openclaw.astro
  • packages/landing/src/pages/skills.astro
  • packages/landing/src/styles/theme-tokens.ts
  • packages/landing/src/use-case-showcases.ts
💤 Files with no reviewable changes (4)
  • packages/landing/src/pages/skills.astro
  • packages/landing/src/pages/memory.astro
  • packages/landing/public/asciinema-player/asciinema-player.css
  • packages/landing/src/pages/for/[useCase].astro

Comment on lines +22 to +25
const hasIssues =
data.unreconciled_count > 0 ||
(data.new_variances?.length ?? 0) > 0 ||
(data.approaching_deadlines?.length ?? 0) > 0;
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

Include payment_risks in issue detection and alert payload.

payment_risks is part of ReconciliationData but is ignored in Line 22-Line 25 and in the saved alert body/metadata, so risk-only windows can be silently dropped.

Suggested fix
   const hasIssues =
     data.unreconciled_count > 0 ||
     (data.new_variances?.length ?? 0) > 0 ||
-    (data.approaching_deadlines?.length ?? 0) > 0;
+    (data.approaching_deadlines?.length ?? 0) > 0 ||
+    (data.payment_risks?.length ?? 0) > 0;
@@
   if (data.approaching_deadlines?.length) {
     parts.push(`Deadlines: ${data.approaching_deadlines.join("; ")}`);
   }
+  if (data.payment_risks?.length) {
+    parts.push(`Payment risks: ${data.payment_risks.join("; ")}`);
+  }
@@
       unreconciled_count: data.unreconciled_count,
       variance_count: data.new_variances?.length ?? 0,
+      payment_risk_count: data.payment_risks?.length ?? 0,
     },
   });

Also applies to: 36-38, 44-48

🤖 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/finance/models/reactions/reconciliation-monitor.reaction.ts` around
lines 22 - 25, The issue: windows with only payment_risks are ignored; update
the detection and alert payload to include payment_risks. Modify the boolean
computation in hasIssues (the expression that references
data.unreconciled_count, data.new_variances, data.approaching_deadlines) to also
check (data.payment_risks?.length ?? 0) > 0, and ensure the saved alert
body/metadata (the object constructed where the alert payload is built further
down in the reaction) includes payment_risks so risk-only windows are captured
and persisted; update the analogous checks at the other occurrences mentioned
(the blocks around lines where hasIssues is evaluated and where the alert
body/metadata are assembled).

Comment on lines +8 to +28
```
lobu-crm/
├── lobu.toml # Agent + memory config
├── connectors/
│ ├── github.yaml # Built-in connector (just config)
│ ├── x.yaml # Built-in connector
│ ├── hackernews.yaml # Built-in connector
│ ├── changelog-watch.yaml # Built-in connector (website)
│ ├── funnel-form.yaml # Custom connector manifest
│ └── funnel-form.connector.ts # Custom connector implementation
├── models/
│ ├── schema.yaml # Entities, relationships, watchers
│ └── reactions/
│ ├── inbound-triage.reaction.ts # Runs after watcher extraction
│ └── funnel-digest.reaction.ts # Runs after watcher extraction
└── agents/crm/
├── SOUL.md # Agent personality
├── IDENTITY.md # Agent identity
├── USER.md # User context
└── skills/crm-ops/SKILL.md # Agent skill
```
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 language identifier to fenced code block.

The directory structure code block is missing a language specifier. Add text or plaintext after the opening backticks for proper rendering.

📝 Proposed fix
-```
+```text
 lobu-crm/
 ├── lobu.toml                              # Agent + memory config

Based on learnings: Static analysis flagged this as a markdown best practice violation.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
lobu-crm/
├── lobu.toml # Agent + memory config
├── connectors/
│ ├── github.yaml # Built-in connector (just config)
│ ├── x.yaml # Built-in connector
│ ├── hackernews.yaml # Built-in connector
│ ├── changelog-watch.yaml # Built-in connector (website)
│ ├── funnel-form.yaml # Custom connector manifest
│ └── funnel-form.connector.ts # Custom connector implementation
├── models/
│ ├── schema.yaml # Entities, relationships, watchers
│ └── reactions/
│ ├── inbound-triage.reaction.ts # Runs after watcher extraction
│ └── funnel-digest.reaction.ts # Runs after watcher extraction
└── agents/crm/
├── SOUL.md # Agent personality
├── IDENTITY.md # Agent identity
├── USER.md # User context
└── skills/crm-ops/SKILL.md # Agent skill
```
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 8-8: 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 `@examples/lobu-crm/README.md` around lines 8 - 28, The fenced code block in
the README.md directory listing is missing a language specifier; update the
opening triple backticks for the block that begins with "lobu-crm/" to include a
language identifier such as text or plaintext (e.g., change ``` to ```text) so
the directory tree renders correctly; locate the block in
examples/lobu-crm/README.md and modify the opening fence accordingly.

Comment on lines +672 to +678
function findConnectorFile(slug: string): { abs: string; rel: string } {
const connectorsDir = resolve(examplesDir, slug, "connectors");
const file = readdirSync(connectorsDir).find((f) =>
f.endsWith(".connector.ts")
);
if (!file) throw new Error(`No *.connector.ts in ${connectorsDir}`);
return {
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

Enforce exactly one connector file per use-case slug.

At Line 674, selecting the first *.connector.ts match is implicit and can become nondeterministic if a second connector file appears. Fail fast when count is not exactly one.

Suggested fix
 function findConnectorFile(slug: string): { abs: string; rel: string } {
   const connectorsDir = resolve(examplesDir, slug, "connectors");
-  const file = readdirSync(connectorsDir).find((f) =>
-    f.endsWith(".connector.ts")
-  );
-  if (!file) throw new Error(`No *.connector.ts in ${connectorsDir}`);
+  const files = readdirSync(connectorsDir)
+    .filter((f) => f.endsWith(".connector.ts"))
+    .sort();
+  if (files.length !== 1) {
+    throw new Error(
+      `Expected exactly 1 *.connector.ts in ${connectorsDir}, found ${files.length}`
+    );
+  }
+  const file = files[0];
   return {
     abs: resolve(connectorsDir, file),
     rel: `connectors/${file}`,
   };
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function findConnectorFile(slug: string): { abs: string; rel: string } {
const connectorsDir = resolve(examplesDir, slug, "connectors");
const file = readdirSync(connectorsDir).find((f) =>
f.endsWith(".connector.ts")
);
if (!file) throw new Error(`No *.connector.ts in ${connectorsDir}`);
return {
function findConnectorFile(slug: string): { abs: string; rel: string } {
const connectorsDir = resolve(examplesDir, slug, "connectors");
const files = readdirSync(connectorsDir)
.filter((f) => f.endsWith(".connector.ts"))
.sort();
if (files.length !== 1) {
throw new Error(
`Expected exactly 1 *.connector.ts in ${connectorsDir}, found ${files.length}`
);
}
const file = files[0];
return {
abs: resolve(connectorsDir, file),
rel: `connectors/${file}`,
};
}
🤖 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 672 - 678, The
findConnectorFile function currently picks the first file matching
*.connector.ts which can be nondeterministic; instead read all matches using
readdirSync(connectorsDir).filter(f => f.endsWith(".connector.ts")), then if the
resulting array length !== 1 throw a clear Error (include connectorsDir and the
list or count) to fail fast; when exactly one match exists, return the same {
abs, rel } values as before using that single filename.

{
role: "bot",
text: "You can change the model from your settings opens a scoped page with your current agent config.",
text: "You can change the model from your settings, opens a scoped page with your current agent config.",
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 the settings-link bot copy grammar.

Line 108 reads as a broken sentence and is hard to parse in-chat.

Suggested copy fix
-      text: "You can change the model from your settings, opens a scoped page with your current agent config.",
+      text: "You can change the model from your settings. It opens a scoped page with your current agent config.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
text: "You can change the model from your settings, opens a scoped page with your current agent config.",
text: "You can change the model from your settings. It opens a scoped page with your current agent config.",
🤖 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/chat-scenarios.ts` at line 108, The bot copy for the
settings link in packages/landing/src/chat-scenarios.ts is a broken sentence;
update the object property text (the "text" value used for the settings-link) to
a single clear sentence such as: "You can change the model from Settings — this
opens a scoped page with your current agent configuration." Replace the existing
malformed string with this corrected sentence so the in-chat message reads
clearly.

- drop unused linkTabsToCampaigns prop (LandingPage + [useCase].astro)
- reaction save() returns Promise<unknown> (runtime does not return {event_id})
- fix /docs/reference -> /reference link prefix in sync-from-github
- add orphaned lobu-apply doc to the Reference sidebar
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