feat: Add lead-outreach-agent kit#198
Conversation
A kit that turns a lead (name, company, website, tone) into a personalized cold email + follow-up, grounded on the company's own website content via a Firecrawl + LLM Lamatic flow, with a Next.js app UI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace scaffold with the real flow exported from Lamatic Studio (API Request →
Generate Text on Groq llama-3.3-70b → API Response returning {subject, email,
followUp}); add prompts/, model-configs/, and update docs to match.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Important Review skippedNo new commits to review since the last review. ⚙️ Run configurationConfiguration used: Repository UI (base), Organization UI (inherited) Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughAdds a new lead-outreach-agent kit with Lamatic flow definitions, prompts, constitution, kit metadata, and a Next.js app that generates outreach drafts from lead details and tone. ChangesLead Outreach Agent Kit
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
:robot_face: AgentKit Structural ValidationNew Contributions Detected
Check Results
🎉 All checks passed! This contribution follows the AgentKit structure. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 13
🤖 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 `@kits/lead-outreach-agent/apps/actions/generate.ts`:
- Around line 38-43: Add minimal server-side validation in generate’s action
before calling lamaticClient.executeFlow, because direct callers can bypass the
client-side checks from page.tsx. Use the existing generate flow entry point and
validate input.name, input.company, and input.website as non-empty strings, with
a basic URL format check for website, then only proceed to executeFlow when the
payload is clean.
- Around line 50-51: The OutreachDraft parsing in generate.ts currently lets a
raw JSON.parse SyntaxError bubble up to the user; update the parsing path around
the draft assignment so malformed LLM output is caught and rethrown with a
clear, user-friendly message. Keep the behavior in the generate flow intact, but
wrap the typeof answer === "string" branch in a try/catch (or equivalent) and
throw a contextual error that references the invalid LLM response, so the catch
block reports something readable instead of the raw SyntaxError.
- Around line 50-55: The draft validation in generate.ts only checks subject and
email, so an omitted followUp can slip through and break the UI. Update the
validation around the OutreachDraft parsing to also require followUp, and throw
the same kind of error when it is missing; use the existing draft object and its
subject/email check as the place to add the followUp guard so the shape matches
what the UI expects.
In `@kits/lead-outreach-agent/apps/app/globals.css`:
- Around line 5-12: The global theme styles in globals.css use hard-coded color
literals instead of the required CSS variables. Update the :root and body rules
to use existing theme tokens / CSS custom properties for the background and
foreground colors, keeping the styling in globals.css tokenized and aligned with
the kit app guideline.
In `@kits/lead-outreach-agent/apps/app/page.tsx`:
- Around line 27-49: The Page form currently uses local useState and manual
validation; refactor it to use react-hook-form with a zod schema for the
outreach fields. Update the Page component to define a schema and FormValues,
wire in zodResolver, and replace the custom set/onSubmit logic with handleSubmit
plus register/error handling while still calling generateOutreach with the
validated values.
- Around line 9-25: Replace the hand-rolled CopyButton and Card usage in
page.tsx with shadcn/ui primitives so the UI follows kit conventions. Update the
CopyButton component to use the shadcn Button API for the clipboard action and
state display, and swap the custom Card markup in the page component for the
shadcn Card family (Card, CardHeader, CardContent, etc.) while keeping the same
layout and behavior. Use the existing CopyButton and page component structure to
locate the changes.
- Around line 14-18: The onClick handler in the copy action ignores failures
from navigator.clipboard.writeText, so copied state can be shown even when the
promise rejects. Update the handler in the relevant copy component to await or
chain the clipboard promise and only call setCopied(true) after a successful
write, with error handling that avoids setting the success state on failure and
leaves the feedback accurate.
In `@kits/lead-outreach-agent/apps/lib/lamatic-client.ts`:
- Around line 4-8: The `workflowId` validation is duplicated:
`lamatic-client.ts` already guards
`config.flows["lead-outreach-agent"].workflowId` at module load, so remove the
extra check in `generate.ts`. Update the `generate` flow to rely on the existing
module-level guard and keep the `LamaticClient`/client construction path
unchanged so there is only one source of truth for this required config.
In `@kits/lead-outreach-agent/apps/next.config.mjs`:
- Around line 3-4: The Next.js build config is skipping ESLint via the
eslint.ignoreDuringBuilds override, so lint failures can slip through. Update
the next.config.mjs configuration to stop bypassing lint during builds, or
ensure the build pipeline invokes a required lint check before merge; use the
existing Next.js config export in this file to locate and adjust the eslint
setting.
In `@kits/lead-outreach-agent/apps/package.json`:
- Line 12: The Lamatic dependency in package.json is using a floating "latest"
version, which can cause installs to drift without a lockfile. Replace the
Lamatic entry in the app’s dependencies with a specific reviewed release version
so builds stay reproducible, and keep the package name identifiable by its
"lamatic" key in package.json.
In `@kits/lead-outreach-agent/apps/README.md`:
- Around line 18-23: The Lamatic Studio location labels for `LAMATIC_API_URL`
and `LAMATIC_PROJECT_ID` are inconsistent with the top-level `README.md`, which
can confuse users. Update the table in the `README` so the paths match the
existing guidance used elsewhere (for example, `Settings → API → Endpoint` and
`Settings → Project ID`), and keep the naming consistent across the
`LEAD_OUTREACH_AGENT` setup instructions.
In `@kits/lead-outreach-agent/flows/lead-outreach-agent.ts`:
- Around line 64-92: Add a grounding/retrieval step before `LLMNode_135` so the
flow uses actual website content instead of only the raw `website` URL. Update
`lead-outreach-agent.ts` to insert a fetch/extraction node (or equivalent
tool-backed step) that resolves the site into usable page text, then pass that
grounded content into `LLMNode_135`’s prompts. Make sure the prompt templates
for `LLMNode_135` consume the fetched findings so the opening line can reference
a real site-specific observation.
In
`@kits/lead-outreach-agent/model-configs/lead-outreach-agent_llmnode-135_generative-model-name.ts`:
- Around line 3-15: The exported generative model config includes a
workspace-specific credentialId that makes the kit brittle across imports;
remove that binding from lead-outreach-agent_llmnode-135_generative-model-name
and leave credential selection to the consumer. Keep the rest of the
generativeModelName entry intact, including configName, model_name,
provider_name, and credential_name, so the config can be re-bound in the target
workspace.
🪄 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: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9d0a82c0-6f87-4322-a0ed-01c9b3d9663d
📒 Files selected for processing (24)
kits/lead-outreach-agent/.env.examplekits/lead-outreach-agent/.gitignorekits/lead-outreach-agent/README.mdkits/lead-outreach-agent/agent.mdkits/lead-outreach-agent/apps/.env.examplekits/lead-outreach-agent/apps/.gitignorekits/lead-outreach-agent/apps/README.mdkits/lead-outreach-agent/apps/actions/generate.tskits/lead-outreach-agent/apps/app/globals.csskits/lead-outreach-agent/apps/app/layout.tsxkits/lead-outreach-agent/apps/app/page.tsxkits/lead-outreach-agent/apps/lib/config.tskits/lead-outreach-agent/apps/lib/lamatic-client.tskits/lead-outreach-agent/apps/next.config.mjskits/lead-outreach-agent/apps/package.jsonkits/lead-outreach-agent/apps/postcss.config.mjskits/lead-outreach-agent/apps/tailwind.config.tskits/lead-outreach-agent/apps/tsconfig.jsonkits/lead-outreach-agent/constitutions/default.mdkits/lead-outreach-agent/flows/lead-outreach-agent.tskits/lead-outreach-agent/lamatic.config.tskits/lead-outreach-agent/model-configs/lead-outreach-agent_llmnode-135_generative-model-name.tskits/lead-outreach-agent/prompts/lead-outreach-agent_llmnode-135_system_0.mdkits/lead-outreach-agent/prompts/lead-outreach-agent_llmnode-135_user_1.md
| function CopyButton({ text }: { text: string }) { | ||
| const [copied, setCopied] = useState(false); | ||
| return ( | ||
| <button | ||
| type="button" | ||
| onClick={() => { | ||
| void navigator.clipboard.writeText(text); | ||
| setCopied(true); | ||
| setTimeout(() => setCopied(false), 1500); | ||
| }} | ||
| className="inline-flex items-center gap-1.5 rounded-md border border-white/15 px-2.5 py-1 text-xs text-white/70 transition hover:bg-white/10" | ||
| > | ||
| {copied ? <Check size={13} /> : <Copy size={13} />} | ||
| {copied ? "Copied" : "Copy"} | ||
| </button> | ||
| ); | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Use shadcn/ui components instead of custom-built CopyButton and Card.
The kit coding guidelines require shadcn/ui components. CopyButton and Card are hand-rolled here. Replacing them with shadcn/ui's Button and Card primitives ensures consistency across kits and reduces maintenance surface area.
Also applies to: 119-131
🤖 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 `@kits/lead-outreach-agent/apps/app/page.tsx` around lines 9 - 25, Replace the
hand-rolled CopyButton and Card usage in page.tsx with shadcn/ui primitives so
the UI follows kit conventions. Update the CopyButton component to use the
shadcn Button API for the clipboard action and state display, and swap the
custom Card markup in the page component for the shadcn Card family (Card,
CardHeader, CardContent, etc.) while keeping the same layout and behavior. Use
the existing CopyButton and page component structure to locate the changes.
Source: Coding guidelines
| "lint": "next lint" | ||
| }, | ||
| "dependencies": { | ||
| "lamatic": "latest", |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- file: kits/lead-outreach-agent/apps/package.json ---\n'
cat -n kits/lead-outreach-agent/apps/package.json
printf '\n--- nearby package manifests ---\n'
git ls-files 'kits/*/apps/package.json' | sed -n '1,40p'
printf '\n--- search for lamatic usage and version pins ---\n'
rg -n '"lamatic"|lamatic' kits/ -g 'package.json' -g 'package-lock.json' -g 'pnpm-lock.yaml' -g 'yarn.lock' -g 'bun.lockb' || trueRepository: Lamatic/AgentKit
Length of output: 245
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- file: kits/lead-outreach-agent/apps/package.json ---'
cat -n kits/lead-outreach-agent/apps/package.json
echo
echo '--- nearby package manifests ---'
git ls-files 'kits/*/apps/package.json' | sed -n '1,80p'
echo
echo '--- search for lamatic usage and version pins ---'
rg -n '"lamatic"|lamatic' kits/ -g 'package.json' -g 'package-lock.json' -g 'pnpm-lock.yaml' -g 'yarn.lock' -g 'bun.lockb' || trueRepository: Lamatic/AgentKit
Length of output: 10163
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- files under kits/lead-outreach-agent/apps ---'
git ls-files 'kits/lead-outreach-agent/apps/*' | sed -n '1,120p'
echo
echo '--- lockfile presence ---'
for f in \
kits/lead-outreach-agent/apps/package-lock.json \
kits/lead-outreach-agent/apps/pnpm-lock.yaml \
kits/lead-outreach-agent/apps/yarn.lock \
kits/lead-outreach-agent/apps/bun.lockb
do
if [ -f "$f" ]; then
echo "FOUND $f"
else
echo "MISSING $f"
fi
doneRepository: Lamatic/AgentKit
Length of output: 1071
Mission: pin Lamatic to a reviewed release.
latest makes installs drift, and this app has no lockfile to freeze the resolved SDK version.
🤖 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 `@kits/lead-outreach-agent/apps/package.json` at line 12, The Lamatic
dependency in package.json is using a floating "latest" version, which can cause
installs to drift without a lockfile. Replace the Lamatic entry in the app’s
dependencies with a specific reviewed release version so builds stay
reproducible, and keep the package name identifiable by its "lamatic" key in
package.json.
| "id": "LLMNode_135", | ||
| "type": "dynamicNode", | ||
| "position": { | ||
| "x": 0, | ||
| "y": 0 | ||
| }, | ||
| "data": { | ||
| "nodeId": "LLMNode", | ||
| "values": { | ||
| "tools": [], | ||
| "prompts": [ | ||
| { | ||
| "id": "187c2f4b-c23d-4545-abef-73dc897d6b7b", | ||
| "role": "system", | ||
| "content": "@prompts/lead-outreach-agent_llmnode-135_system_0.md" | ||
| }, | ||
| { | ||
| "id": "187c2f4b-c23d-4545-abef-73dc897d6b7d", | ||
| "role": "user", | ||
| "content": "@prompts/lead-outreach-agent_llmnode-135_user_1.md" | ||
| } | ||
| ], | ||
| "memories": "[]", | ||
| "messages": "[]", | ||
| "nodeName": "Generate Text", | ||
| "attachments": "", | ||
| "credentials": "", | ||
| "generativeModelName": "@model-configs/lead-outreach-agent_llmnode-135_generative-model-name.ts" | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Mission update: add a real grounding step before the LLM.
LLMNode_135 only sees the raw website URL here; there is no fetch/retrieval step, so the model cannot actually open with a site-specific observation. As written, the outreach copy will still be guesswork.
🤖 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 `@kits/lead-outreach-agent/flows/lead-outreach-agent.ts` around lines 64 - 92,
Add a grounding/retrieval step before `LLMNode_135` so the flow uses actual
website content instead of only the raw `website` URL. Update
`lead-outreach-agent.ts` to insert a fetch/extraction node (or equivalent
tool-backed step) that resolves the site into usable page text, then pass that
grounded content into `LLMNode_135`’s prompts. Make sure the prompt templates
for `LLMNode_135` consume the fetched findings so the opening line can reference
a real site-specific observation.
- generate.ts: add server-side input validation (name/company/website + URL), wrap JSON.parse in a friendly error, guard followUp, drop the duplicate workflowId check (module-level guard covers it) - page.tsx: only show "Copied" after a successful clipboard write - globals.css: tokenize theme colors as CSS variables - next.config.mjs: stop bypassing ESLint on build; add .eslintrc + eslint deps - package.json: pin lamatic to ^0.3.2 (was "latest") - model-config: drop workspace-specific credentialId for portability - apps/README: align Studio setting paths with the top-level README Verified with `next build` (compile + lint + types all pass). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks for the thorough review! Addressed the correctness & config items in the latest commit: ✅ Fixed
⏭️ Intentionally skipped (keeping the kit minimal & focused)
The kit builds and runs end-to-end against the deployed flow. 🙏 |
|
@coderabbitai review |
✅ Action performedReview finished.
|
Lead Outreach Agent
Turns a single lead — name, company, website, tone — into a personalized cold email + follow-up, so outreach sounds researched instead of generic.
Type: kit (one Lamatic flow + a Next.js app)
Flow (3 nodes):
API Request— inputs:name,company,website,toneGenerate Text— Groqllama-3.3-70b-versatile; personalized, tone-matched, returns strict JSON; instructed not to fabricate facts it isn't sure aboutAPI Response— returnsanswer = { subject, email, followUp }App: a thin Next.js UI (server action → Lamatic SDK) that collects the lead and renders the draft with copy buttons.
Why: writing a good cold email means researching the prospect and drafting both the email and a follow-up — minutes per lead that don't scale. This does the drafting and keeps the copy specific to the company.
Submitted for the AgentKit Challenge.
🤖 Generated with Claude Code
flows/lead-outreach-agent.ts:graphqlNode) forname,company,website, andtonellama-3.3-70b-versatilegraphqlResponseNode) returninganswerprompts/..._system_0.mdprompts/..._user_1.mdmodel-configs/..._generative-model-name.tsconstitutions/default.mdlamatic.config.tsfor packaging, docs, and deploy links.apps/with:app/page.tsxform UI to collect lead details and render copyable resultsactions/generate.tsserver action that executes the Lamatic flowlib/config.tsandlib/lamatic-client.tsfor env + SDK setupapp/layout.tsx,app/globals.css, and build/tooling configs (package.json,tsconfig.json,tailwind.config.ts,postcss.config.mjs,next.config.mjs)README.mdandapps/README.mdagent.md.env.exampleand.gitignorefiles for both kit and app