Johann Cavallucci

Job hunting is time-consuming: scroll Welcome to the Jungle or LinkedIn, open every listing, read the description, check experience, English level, stack, seniority… and often a single detail disqualifies the role after ten minutes of reading.
Arti is a personal agent that does that work for me. It has my context — CV, preferences, what I’m actually looking for — explores Welcome to the Jungle and LinkedIn, pre-filters by role, reads the descriptions, scores each offer, and only keeps those above a configurable threshold (e.g. ~70%). It sends me those offers over iMessage, several times a day: fresh jobs, already scored, with an actionable summary and the link to apply.
I own it end-to-end as Full Stack and AI engineer — a side project built for my own search, not a polished public product.
The product idea is simple: cut the noise before I ever open a tab. Everything lands where I already am — iMessage — without another dashboard to babysit.
Key features:
#70, #69…), read or update the minimum score threshold.Extras that keep the signal clean: title / experience / role-focus pre-filters, URL deduplication, and multi-source ingestion (WTTJ + LinkedIn).

| Technology | Role in the project |
|---|---|
| TypeScript | Single language across the monorepo (apps + packages) |
| pnpm workspaces | Package split (core, db, sources, pipeline) + apps |
| Nitro | iMessage agent server (webhooks, runtime) |
| Chat SDK + Sendblue | Receive / send iMessage, reactions (like) |
| Vercel AI SDK + AI Gateway | LLM calls (scoring, chat, cover letters) through a unified gateway |
| DeepSeek (via gateway) | Model used for match, chat, and cover letters |
| PostgreSQL | Persist offers, letters, and seen-URL history |
| Drizzle ORM | SQL schema, queries, migrations |
| Zod | Validate prefs / profiles / structured LLM outputs |
| Custom sources (WTTJ Algolia + LinkedIn guest) | Ingest listings and offer details |
| Cron / sync worker | Periodic matching pipeline runs |
| evlog | Observability for LLM calls (tokens, cost, timing) |
Architecture in short: monorepo → sources scrape WTTJ / LinkedIn → pipeline pre-filters, calls the LLM to score and summarize, writes to Postgres → iMessage notification (Sendblue). In parallel, the Nitro app listens for messages: deterministic commands (refresh, threshold, listing, letter) plus a tool-using agent fallback for natural language.
Building a useful agent means the hard part is judgment, not just plumbing:
Arti already saves me a lot of time: every offer I receive is pre-filtered and relevant. It doesn’t replace all manual search, but it cuts most of the time wasted on roles that are incompatible from the first line of the description.
Next: harden the sources, improve cover-letter quality, and keep tuning the matching loop so the bar stays high as my search evolves.