-
Notifications
You must be signed in to change notification settings - Fork 20
feat(landing): per-use-case snippet tabs, connector logo wall, drop asciinema, simplify nav #988
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
dab9329
72f2bf2
2bf5954
d84ee87
2544d29
e19383b
7b69f17
419dc66
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,40 +1,50 @@ | ||
| /** | ||
| * Reaction for the `reconciliation-monitor` watcher. | ||
| * | ||
| * Persists any variance flagged during the daily 6am sweep as a durable | ||
| * `variance_flag` event tied to the affected account. Downstream agents | ||
| * (close-of-month rollup, audit prep) consume these events instead of | ||
| * re-extracting variances from the raw transaction stream. | ||
| * Persists variance events when unreconciled transactions or new anomalies | ||
| * are detected during the daily reconciliation pass. | ||
| */ | ||
| import type { ReactionContext } from "@lobu/connector-sdk"; | ||
| import type { ReactionClient, ReactionContext } from "@lobu/connector-sdk"; | ||
|
|
||
| interface ReconciliationData { | ||
| variances?: Array<{ | ||
| account: string; | ||
| amount: number; | ||
| direction: "over" | "under"; | ||
| reason: string; | ||
| }>; | ||
| unreconciled_count?: number; | ||
| unreconciled_count: number; | ||
| new_variances: string[]; | ||
| approaching_deadlines: string[]; | ||
| payment_risks?: string[]; | ||
| } | ||
|
|
||
| export default async (ctx: ReactionContext, client: any): Promise<void> => { | ||
| export default async ( | ||
| ctx: ReactionContext, | ||
| client: ReactionClient | ||
| ): Promise<void> => { | ||
| const data = ctx.extracted_data as ReconciliationData; | ||
| const variances = data.variances ?? []; | ||
| if (variances.length === 0) return; | ||
|
|
||
| for (const v of variances) { | ||
| await client.knowledge.save({ | ||
| entity_ids: ctx.entities.map((e) => e.id), | ||
| content: `Variance ${v.direction} on ${v.account}: ${v.amount} — ${v.reason}`, | ||
| semantic_type: "variance_flag", | ||
| metadata: { | ||
| account: v.account, | ||
| amount: v.amount, | ||
| direction: v.direction, | ||
| window_id: ctx.window.id, | ||
| unreconciled_count: data.unreconciled_count ?? null, | ||
| }, | ||
| }); | ||
| const hasIssues = | ||
| data.unreconciled_count > 0 || | ||
| (data.new_variances?.length ?? 0) > 0 || | ||
| (data.approaching_deadlines?.length ?? 0) > 0; | ||
|
|
||
| if (!hasIssues) return; | ||
|
|
||
| const parts: string[] = []; | ||
| if (data.unreconciled_count > 0) { | ||
| parts.push(`${data.unreconciled_count} unreconciled transactions`); | ||
| } | ||
| if (data.new_variances?.length) { | ||
| parts.push(`Variances: ${data.new_variances.join("; ")}`); | ||
| } | ||
| if (data.approaching_deadlines?.length) { | ||
| parts.push(`Deadlines: ${data.approaching_deadlines.join("; ")}`); | ||
| } | ||
|
|
||
| await client.knowledge.save({ | ||
| entity_ids: ctx.entities.map((e) => e.id), | ||
| content: parts.join("\n"), | ||
| semantic_type: "reconciliation_alert", | ||
| metadata: { | ||
| window_id: ctx.window.id, | ||
| unreconciled_count: data.unreconciled_count, | ||
| variance_count: data.new_variances?.length ?? 0, | ||
| }, | ||
| }); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,37 @@ | ||||||||||||||||||||||||||||||||||||||||||||
| # lobu-crm — Reference example | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| A funnel CRM agent that tracks GitHub stars, X mentions, HN posts, and demo-form submissions. | ||||||||||||||||||||||||||||||||||||||||||||
| Use this as a starting point for new projects — it shows every Lobu concept in one place. | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ## Structure | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||
| 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 | ||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+8
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add language identifier to fenced code block. The directory structure code block is missing a language specifier. Add 📝 Proposed fix-```
+```text
lobu-crm/
├── lobu.toml # Agent + memory configBased on learnings: Static analysis flagged this as a markdown best practice violation. 📝 Committable suggestion
Suggested change
🧰 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 |
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ## Key files to read | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| | File | What it shows | | ||||||||||||||||||||||||||||||||||||||||||||
| |------|--------------| | ||||||||||||||||||||||||||||||||||||||||||||
| | `lobu.toml` | Agent config, providers, network allowlist | | ||||||||||||||||||||||||||||||||||||||||||||
| | `models/schema.yaml` | Entity definitions + watcher cron + extraction schema | | ||||||||||||||||||||||||||||||||||||||||||||
| | `connectors/funnel-form.connector.ts` | Custom connector with typed checkpoint + config | | ||||||||||||||||||||||||||||||||||||||||||||
| | `models/reactions/inbound-triage.reaction.ts` | Reaction script with typed `ReactionClient` | | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Include
payment_risksin issue detection and alert payload.payment_risksis part ofReconciliationDatabut 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