Skip to content

Feat/cold email personalization#95

Open
10done wants to merge 4 commits intoLamatic:mainfrom
10done:feat/cold-email-personalization
Open

Feat/cold email personalization#95
10done wants to merge 4 commits intoLamatic:mainfrom
10done:feat/cold-email-personalization

Conversation

@10done
Copy link

@10done 10done commented Mar 23, 2026

Mission Possible

Added Cold Email Personalization Agent Kit — a Next.js automation kit that generates hyper-personalized cold outreach emails for college students applying to engineering opportunities. Users paste a LinkedIn-style profile and their own context, and the agent produces a tailored subject line, email body, and personalization hook using a LLM API via Lamatic flow.

  • New Next.js "Cold Email Personalization" Agent Kit to generate hyper-personalized outreach (subject, body, personalization hook) for college engineering applicants via a Lamatic flow and LLM.
  • Frontend: form page with client validation, per-field character limits, copy-to-clipboard for generated sections, loading/error states, and a Header component.
  • Server/orchestration: server action personalizeColdEmail with runtime input validation, Lamatic flow execution, improved error mapping, and a lazily-initialized Lamatic client (getLamaticClient).
  • Parsing/robustness: parseColdEmailResult that normalizes varied Lamatic/LLM responses, rejects schema-only echoes, and enforces required output fields.
  • UI & styling: five shadcn-style components (Button, Card, Input, Label, Textarea) and Tailwind globals.css with light/dark tokens and animations.
  • Flows/config: Lamatic flow files (config/inputs/meta/README) and orchestrate.js defining expected inputs/outputs; .env.example and .gitignore added; .npmrc for legacy-peer-deps.
  • Tooling: package.json, tsconfig, next.config, postcss config added for kit; README documents setup, required env vars, inputs/outputs, and troubleshooting.
  • Maintenance fixes: pinned deps (lamatic 0.3.2, react-markdown 10.1.0), removed ~40 unused radix/shadcn deps and unused UI components, .env*.local added to .gitignore, and small layout/metadata fixes.

10done added 3 commits March 23, 2026 22:40
Adds a new automation kit that generates hyper-personalized cold outreach
emails for college students applying to engineering internships. Takes
LinkedIn/profile data and student context as inputs and produces a
subject line, email body, and personalization hook via a Gemini-powered
Lamatic flow.

Made-with: Cursor
Deleted 53 unused shadcn/ui components, theme-provider, and the hooks
folder that were copied from the base template but never referenced.
Keeps only the 5 components actually used: button, card, input, label,
textarea.

Made-with: Cursor
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 23, 2026

📝 Walkthrough

Walkthrough

Adds a new "Cold Email Personalization" automation kit: a Next.js app, UI components, server-side orchestration, Lamatic workflow configs, a Lamatic client, result parser, and build/config files to run a Lamatic-powered cold-email generation flow.

Changes

Cohort / File(s) Summary
Project config & tooling
kits/automation/cold-email-personalization/.env.example, kits/automation/cold-email-personalization/.gitignore, kits/automation/cold-email-personalization/.npmrc, kits/automation/cold-email-personalization/package.json, kits/automation/cold-email-personalization/tsconfig.json, kits/automation/cold-email-personalization/postcss.config.mjs, kits/automation/cold-email-personalization/next.config.mjs, kits/automation/cold-email-personalization/components.json
New repo/kit-level config files: env placeholders, ignore rules, npm legacy-peer-deps, package metadata/deps, TypeScript, PostCSS/Tailwind setup, Next config, and Shadcn UI config.
Documentation & metadata
kits/automation/cold-email-personalization/README.md, kits/automation/cold-email-personalization/config.json, kits/automation/cold-email-personalization/flows/cold-email-personalisation/README.md, kits/automation/cold-email-personalization/flows/cold-email-personalisation/meta.json
Kit README, kit config, flow README and flow metadata describing purpose, inputs/outputs, setup, and troubleshooting.
Lamatic workflow files
kits/automation/cold-email-personalization/flows/cold-email-personalisation/config.json, kits/automation/cold-email-personalization/flows/cold-email-personalisation/inputs.json, kits/automation/cold-email-personalization/orchestrate.js
Adds a three-node Lamatic flow (API trigger → LLM → GraphQL response), model input settings, and a JS orchestration config referencing env-based workflowId and API creds.
Server orchestration & client library
kits/automation/cold-email-personalization/actions/orchestrate.ts, kits/automation/cold-email-personalization/lib/lamatic-client.ts, kits/automation/cold-email-personalization/orchestrate.js
Server action personalizeColdEmail with input validation, mapping to flow schema, Lamatic client invocation, response handling and user-facing error mapping; lazy/cached Lamatic client with env validation; JS orchestration config.
Result parsing & utilities
kits/automation/cold-email-personalization/lib/parse-cold-email-result.ts, kits/automation/cold-email-personalization/lib/utils.ts
Robust parser for varied Lamatic result shapes into subject_line, email_body, personalized_hook; cn() utility combining clsx + tailwind-merge.
Next.js app & styling
kits/automation/cold-email-personalization/app/globals.css, kits/automation/cold-email-personalization/app/layout.tsx, kits/automation/cold-email-personalization/app/page.tsx
Global Tailwind theme with dark mode tokens, RootLayout with font/metadata/analytics, and client page ColdEmailPage containing the input form, validation, submission logic, loading state, and result UI with copy-to-clipboard.
UI components
kits/automation/cold-email-personalization/components/header.tsx, kits/automation/cold-email-personalization/components/ui/button.tsx, kits/automation/cold-email-personalization/components/ui/card.tsx, kits/automation/cold-email-personalization/components/ui/input.tsx, kits/automation/cold-email-personalization/components/ui/label.tsx, kits/automation/cold-email-personalization/components/ui/textarea.tsx
Adds header and a set of Shadcn-style UI primitives (Button with variants, Card family, Input, Label, Textarea) implemented with Tailwind and cn utility.
Env/example & gitignore
kits/automation/cold-email-personalization/.env.example, kits/automation/cold-email-personalization/.gitignore
Example env variables for workflow ID and Lamatic API credentials; standard Node/Next ignore rules.

Sequence Diagram

sequenceDiagram
    participant Browser as Browser
    participant Page as ColdEmailPage<br/>(Client)
    participant ServerAction as personalizeColdEmail<br/>(Server)
    participant LamaticClient as LamaticClient<br/>(lib)
    participant LamaticAPI as Lamatic API
    participant Parser as parseColdEmailResult<br/>(lib)

    Browser->>Page: User fills form & submits
    Page->>Page: Validate inputs & enforce limits
    Page->>ServerAction: POST form -> personalizeColdEmail
    ServerAction->>ServerAction: Validate config & workflowId
    ServerAction->>LamaticClient: executeFlow(workflowId, inputs)
    LamaticClient->>LamaticAPI: GraphQL request (uses LAMATIC_API_ envs)
    LamaticAPI-->>LamaticClient: Response (result / error)
    LamaticClient-->>ServerAction: Raw response
    ServerAction->>Parser: parseColdEmailResult(raw result)
    Parser-->>ServerAction: {subject_line, email_body, personalized_hook}
    ServerAction-->>Page: { success: true, data } or { success: false, error }
    Page->>Browser: Render generated output or show error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Fix : Config Removal #42: Changes to Lamatic client initialization and environment-variable handling that overlap with the kit's lamatic-client and env validation.

Suggested reviewers

  • amanintech
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feat/cold email personalization' is directly related to the main change: adding a complete Cold Email Personalization Agent Kit. It clearly summarizes the primary feature being introduced.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

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

Copy link
Contributor

@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: 10

🧹 Nitpick comments (9)
kits/automation/cold-email-personalization/.npmrc (1)

1-1: Document why legacy-peer-deps is required.

This setting bypasses peer dependency checks, which can mask genuine incompatibilities. Consider adding a comment or documenting which specific package conflicts necessitate this workaround (likely React 19 compatibility with older Radix/form libraries).

kits/automation/cold-email-personalization/package.json (1)

16-68: Remove 25 unused Radix UI dependencies to reduce bundle size.

The kit declares 27 Radix UI packages but only imports 2 directly (@radix-ui/react-label and @radix-ui/react-slot). The remaining 25 packages—accordion, alert-dialog, aspect-ratio, avatar, checkbox, collapsible, context-menu, dialog, dropdown-menu, hover-card, menubar, navigation-menu, popover, progress, radio-group, scroll-area, select, separator, slider, switch, tabs, toast, toggle, tooltip—are unused. Removing them reduces bundle bloat and maintenance surface.

kits/automation/cold-email-personalization/lib/lamatic-client.ts (1)

16-20: Remove empty-string fallbacks after strict env checks.

Line 17–19 can hide mapping mistakes by silently creating a client with empty credentials. Since Line 4–14 already fail fast, pass validated values directly.

♻️ Proposed fail-fast refactor
 export const lamaticClient = new Lamatic({
-  endpoint: config.api.endpoint ?? "",
-  projectId: config.api.projectId ?? "",
-  apiKey: config.api.apiKey ?? "",
+  endpoint: config.api.endpoint!,
+  projectId: config.api.projectId!,
+  apiKey: config.api.apiKey!,
 })
kits/automation/cold-email-personalization/components/header.tsx (1)

1-47: Rename component file to PascalCase (Header.tsx).

This component file is in components/ but uses lowercase filename (header.tsx), which conflicts with the repository component naming rule.

As per coding guidelines, "Use PascalCase for React component filenames in the components/ directory".

kits/automation/cold-email-personalization/components/ui/input.tsx (1)

1-21: Rename input.tsx to Input.tsx for guideline compliance.

This React component file lives under components/ and should use PascalCase naming.

As per coding guidelines, "Use PascalCase for React component filenames in the components/ directory".

kits/automation/cold-email-personalization/components/ui/label.tsx (1)

1-1: Rename file to PascalCase (Label.tsx).

label.tsx violates the component filename convention for this directory.

As per coding guidelines, "Use PascalCase for React component filenames in the components/ directory".

kits/automation/cold-email-personalization/components/ui/textarea.tsx (1)

1-1: Rename file to PascalCase (Textarea.tsx).

Current filename textarea.tsx is not aligned with the components naming convention.

As per coding guidelines, "Use PascalCase for React component filenames in the components/ directory".

kits/automation/cold-email-personalization/components/ui/button.tsx (2)

1-1: Rename file to PascalCase (Button.tsx).

button.tsx does not follow the required filename convention for React components.

As per coding guidelines, "Use PascalCase for React component filenames in the components/ directory".


39-56: Default native buttons to type="button" to avoid accidental submits.

Line 52 renders a native <button> path without a default type, so inside forms it will submit unless callers always pass type.

Proposed fix
 function Button({
   className,
   variant,
   size,
   asChild = false,
+  type,
   ...props
 }: React.ComponentProps<'button'> &
   VariantProps<typeof buttonVariants> & {
     asChild?: boolean
   }) {
   const Comp = asChild ? Slot : 'button'

   return (
     <Comp
       data-slot="button"
+      type={asChild ? type : (type ?? 'button')}
       className={cn(buttonVariants({ variant, size, className }))}
       {...props}
     />
   )
 }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d290c7ab-841b-4918-ab67-7609dee882f6

📥 Commits

Reviewing files that changed from the base of the PR and between cd0d519 and 3cc861e.

⛔ Files ignored due to path filters (2)
  • .DS_Store is excluded by !**/.DS_Store
  • kits/automation/cold-email-personalization/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (28)
  • kits/automation/cold-email-personalization/.env.example
  • kits/automation/cold-email-personalization/.gitignore
  • kits/automation/cold-email-personalization/.npmrc
  • kits/automation/cold-email-personalization/README.md
  • kits/automation/cold-email-personalization/actions/orchestrate.ts
  • kits/automation/cold-email-personalization/app/globals.css
  • kits/automation/cold-email-personalization/app/layout.tsx
  • kits/automation/cold-email-personalization/app/page.tsx
  • kits/automation/cold-email-personalization/components.json
  • kits/automation/cold-email-personalization/components/header.tsx
  • kits/automation/cold-email-personalization/components/ui/button.tsx
  • kits/automation/cold-email-personalization/components/ui/card.tsx
  • kits/automation/cold-email-personalization/components/ui/input.tsx
  • kits/automation/cold-email-personalization/components/ui/label.tsx
  • kits/automation/cold-email-personalization/components/ui/textarea.tsx
  • kits/automation/cold-email-personalization/config.json
  • kits/automation/cold-email-personalization/flows/cold-email-personalisation/README.md
  • kits/automation/cold-email-personalization/flows/cold-email-personalisation/config.json
  • kits/automation/cold-email-personalization/flows/cold-email-personalisation/inputs.json
  • kits/automation/cold-email-personalization/flows/cold-email-personalisation/meta.json
  • kits/automation/cold-email-personalization/lib/lamatic-client.ts
  • kits/automation/cold-email-personalization/lib/parse-cold-email-result.ts
  • kits/automation/cold-email-personalization/lib/utils.ts
  • kits/automation/cold-email-personalization/next.config.mjs
  • kits/automation/cold-email-personalization/orchestrate.js
  • kits/automation/cold-email-personalization/package.json
  • kits/automation/cold-email-personalization/postcss.config.mjs
  • kits/automation/cold-email-personalization/tsconfig.json

- Add .env.local and .env*.local to .gitignore to prevent secret commits
- Remove quotes from .env.example values (dotenv-linter compliance)
- Fix layout.tsx metadata (remove v0 placeholders)
- Refactor lamatic-client to lazy getter so init errors are caught by the action's try/catch
- Add server-side input validation in orchestrate.ts (mirrors client-side guards)
- Tighten parser to reject partial outputs with empty subject_line or email_body
- Pin lamatic to 0.3.2 and react-markdown to 10.1.0 (was "latest")
- Remove ~40 unused radix/shadcn dependencies from package.json

Made-with: Cursor
Copy link
Contributor

@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 (1)
kits/automation/cold-email-personalization/lib/parse-cold-email-result.ts (1)

19-63: ⚠️ Potential issue | 🟠 Major

Fail fast on partial outputs and nested schema echoes.

ColdEmailOutput and the page state both treat personalized_hook as required, but this still coerces it to "". Also, isSchemaEchoNotEmailData() only becomes actionable for the top-level object, so string or nested schema echoes still degrade to a generic parser failure even though personalizeColdEmail() already catches parser errors cleanly.

💡 Tighten the parser contract and preserve the Lamatic config error
 function parseFromJsonString(raw: string): ColdEmailOutput {
   const cleaned = stripJsonFences(raw)
-  const parsed = JSON.parse(cleaned) as Record<string, unknown>
+  const parsed = JSON.parse(cleaned)
+  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
+    throw new Error("Workflow returned JSON that is not an object.")
+  }
+
+  const record = parsed as Record<string, unknown>
+  if (isSchemaEchoNotEmailData(record)) throw new Error(LAMATIC_SCHEMA_ECHO_MESSAGE)
 
-  const subject_line = parsed.subject_line
-  const email_body = parsed.email_body
-  const personalized_hook = parsed.personalized_hook
+  const subject_line = record.subject_line
+  const email_body = record.email_body
+  const personalized_hook = record.personalized_hook
 
   if (
     typeof subject_line !== "string" || subject_line.trim() === "" ||
-    typeof email_body !== "string" || email_body.trim() === ""
+    typeof email_body !== "string" || email_body.trim() === "" ||
+    typeof personalized_hook !== "string" || personalized_hook.trim() === ""
   ) {
-    throw new Error("Parsed JSON is missing required subject_line or email_body.")
+    throw new Error("Parsed JSON is missing required subject_line, email_body, or personalized_hook.")
   }
 
   return {
     subject_line,
     email_body,
-    personalized_hook: typeof personalized_hook === "string" ? personalized_hook : "",
+    personalized_hook,
   }
 }
 
 function isColdEmailShape(o: Record<string, unknown>): boolean {
   return (
     typeof o.subject_line === "string" && o.subject_line.trim() !== "" &&
-    typeof o.email_body === "string" && o.email_body.trim() !== ""
+    typeof o.email_body === "string" && o.email_body.trim() !== "" &&
+    typeof o.personalized_hook === "string" && o.personalized_hook.trim() !== ""
   )
 }
 
 function fromShape(o: Record<string, unknown>): ColdEmailOutput {
   return {
     subject_line: o.subject_line as string,
     email_body: o.email_body as string,
-    personalized_hook: typeof o.personalized_hook === "string" ? o.personalized_hook : "",
+    personalized_hook: o.personalized_hook as string,
   }
 }
 
 function tryParseEmailJsonString(s: string): ColdEmailOutput | null {
   const t = s.trim()
   if (t.length < 15 || !t.includes("subject_line")) return null
   try {
     return parseFromJsonString(t)
-  } catch {
+  } catch (error) {
+    if (error instanceof Error && error.message === LAMATIC_SCHEMA_ECHO_MESSAGE) throw error
     return null
   }
 }
 
 function findEmailObject(obj: unknown, depth = 0): ColdEmailOutput | null {
@@
   const r = obj as Record<string, unknown>
+  if (isSchemaEchoNotEmailData(r)) {
+    throw new Error(LAMATIC_SCHEMA_ECHO_MESSAGE)
+  }
 
   if (isColdEmailShape(r)) return fromShape(r)

Also applies to: 85-87, 122-165


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b51a404a-1e2c-49b0-adcd-0993bd7dd8dc

📥 Commits

Reviewing files that changed from the base of the PR and between 3cc861e and f33498c.

📒 Files selected for processing (7)
  • kits/automation/cold-email-personalization/.env.example
  • kits/automation/cold-email-personalization/.gitignore
  • kits/automation/cold-email-personalization/actions/orchestrate.ts
  • kits/automation/cold-email-personalization/app/layout.tsx
  • kits/automation/cold-email-personalization/lib/lamatic-client.ts
  • kits/automation/cold-email-personalization/lib/parse-cold-email-result.ts
  • kits/automation/cold-email-personalization/package.json
✅ Files skipped from review due to trivial changes (4)
  • kits/automation/cold-email-personalization/.env.example
  • kits/automation/cold-email-personalization/.gitignore
  • kits/automation/cold-email-personalization/package.json
  • kits/automation/cold-email-personalization/app/layout.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • kits/automation/cold-email-personalization/lib/lamatic-client.ts
  • kits/automation/cold-email-personalization/actions/orchestrate.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants