docs: update README and SECURITY for Twenty CRM sync, add CSV templates and scripts

This commit is contained in:
Prad Nukala committed 2026-08-26 11:54:32 -04:00
1 parent f2fda73b52
commit 7007c4aa9d
9 files changed
+22 -6

No files matched your search

+7 -5
View File
@@ -150,8 +150,8 @@ Postings are treated as untrusted input (the workflow follows no instructions em
- **`/interview`** preps you for a scheduled interview on a tracked application. It builds a stage-specific prep pack from the application's archive (the exact posting, the CV and cover letter the interviewer actually read, feedback recorded from earlier rounds), researches the company and interviewers with a verify-before-use rule, maps likely questions to your STAR examples, and offers a mock interview following the roleplay protocol in `07-interview-prep.md`. Gaps get honest bridge answers, never invented experience.
- **`/outcome`** records what happened to an application - interview stages, offers, rejections, silence. It archives the submitted CV, cover letter, and posting text into `documents/applications/<company>_<role>/`, keeps `outcome.md` in the format `/setup` Path A parses, and updates the tracker. It also owns the stretch before there is an outcome to record: `/outcome followup` surfaces open applications that have gone quiet (default 10 days), drafts a short channel-appropriate follow-up in your writing style using only claims from the materials you already submitted (drafts only, never sends; at most twice per application), and offers a thank-you note in the same turn an interview stage is recorded. Once a few applications resolve, it points you back to `/setup` to calibrate the fit framework from what actually got interviews.
- **`/notion-sync`** publishes a one-way, read-only view of the pipeline into a Notion database via the official Notion MCP server (OAuth, no API keys) - one row per ranked job plus every tracked application, with a write-once briefing page per row. The repo files stay the system of record: nothing syncs back, and documents sync as filenames only. Complements `/html-report`: that is the deep offline dashboard you regenerate at your desk; this is the glanceable live view from anywhere Notion runs (desktop, web, phone).
- **`/gmail-sync`** reads your Gmail (via the Gmail connector) for status signals on your open applications - interview invites, assessment links, offers, rejections - and proposes them as a batch for you to approve before anything is written to the tracker or `outcome.md`, citing the source email on every proposed change. Offers stop short of proposing `hired`/`offer_declined` since that's your call; conflicting or unmatched signals get flagged for a manual `/outcome` pass instead of guessed.
- **`/sync-twenty`** publishes a one-way, read-only view of the pipeline into a self-hosted [Twenty CRM](https://twenty.com) workspace via its MCP server (OAuth) - one Opportunity per ranked job plus every tracked application, each linked to an enriched Company record (domain, LinkedIn, HQ, revenue - sourced from the local postings database and verified web search). The repo files stay the system of record: nothing syncs back, and documents sync as filenames only. Twenty is the pipeline backend; `/html-report` remains the deep offline dashboard you regenerate at your desk.
- **`/gather-recent-context`** scans your Fastmail inbox (via the Fastmail MCP server) for conversations about active job loops - interview invites, assessments, scheduling, offers - classifies each thread, and syncs a dated summary note onto the matching Opportunity in Twenty via `tools/gather_recent_context.py`. Read-only against the mailbox, summaries only (never raw email bodies), idempotent by thread id.
- **`/rank`** bridges `/scrape` and `/apply`: it batch-scores all newly scraped postings against the fit framework (parallel agents fetch each posting and score the five evaluation dimensions) and returns a ranked shortlist with honest per-job strengths and gaps. Deal-breakers veto, deadlines get urgency flags, dead postings get marked expired. Pick a number and it hands off to the full `/apply` workflow.
- **`/expand`** enriches your profile by scanning public sources you've already linked in it (GitHub repos, portfolio site, Kaggle, Google Scholar) and looking up syllabi for named courses and certifications. Discovered competencies are added to your profile with a source tag. Useful right after `/setup` to surface skills that documents alone don't make explicit.
- **`/upskill`** analyzes the gap between your profile, your tracked job postings, and your ranked-but-untracked postings (`/rank`'s recorded gaps in `seen_jobs.json`) — or a single posting via `/upskill <URL>`. Produces a prioritized heatmap of skill gaps and a learning plan with web-searched study resources and time estimates. Useful for career planning between applications.
@@ -175,10 +175,10 @@ ai-job-search/
│ │ ├── add-portal.md # /add-portal generate a job-portal search skill for your market
│ │ ├── rank.md # /rank triage scraped jobs into a ranked shortlist
│ │ ├── outcome.md # /outcome record application results, archive materials
│ │ ├── gmail-sync.md # /gmail-sync auto-detect application status from Gmail
│ │ ├── interview.md # /interview stage-specific prep pack + mock interview
│ │ ├── html-report.md # /html-report generate application tracker dashboard
│ │ ├── notion-sync.md # /notion-sync one-way pipeline view in a Notion database
│ │ ├── sync-twenty.md # /sync-twenty one-way pipeline + company sync into Twenty CRM
│ │ ├── gather-recent-context.md # /gather-recent-context email context → Twenty CRM notes
│ │ └── reset.md # /reset wipe profile data or documents folder
│ ├── skills/
│ │ ├── job-application-assistant/ # Core application skill
@@ -221,9 +221,11 @@ ai-job-search/
│ ├── convert_salary_excel.py # Convert salary Excel to JSON
│ ├── lint_skills.py # CI lint for skills, commands, settings.json
│ ├── security_guards.py # CI guards: permission allowlist, gitignore rules, manifests
│ ├── twenty_client.py # Minimal Twenty CRM REST client (stdlib only)
│ ├── twenty_enrich.py # Twenty enrichment plan: salary ladder, company fills, name cleanup
│ ├── gather_recent_context.py # Email-thread → opportunity note sync (deterministic core)
│ └── README_SALARY_TOOL.md # Salary tool setup instructions
├── job_scraper/ # Scraper state (seen jobs, results)
├── gmail_sync/ # /gmail-sync state (processed message IDs, last sync date)
├── upskill/ # /upskill report output (markdown reports per run)
├── job_search_tracker.csv # Application tracking spreadsheet
└── SETUP.md # Detailed setup guide
+1 -1
View File
@@ -12,7 +12,7 @@ This is an agentic workflow: an LLM with file access reads untrusted web content
- **Untrusted-input rules**: `/apply` and `/rank` treat posting text as data, never instructions - agents are told not to follow directions embedded in postings and not to fetch URLs found inside posting text (the user-supplied posting URL is the one exception). Reviewer research starts from the company identity the user confirmed, never from links in the posting body.
- **Permission allowlist**: `.claude/settings.json` pre-approves only the specific commands the workflow needs; the `security-guards` CI job fails any PR that widens it, adds package-manifest lifecycle scripts, or weakens the personal-data gitignore rules. Note the allowlist governs Bash commands - the model's native WebFetch/WebSearch tools are outside its reach, which is exactly why the instruction-level rules above exist.
- **Personal data boundaries**: your populated profile, tracker, salary data, and application archive are gitignored; documents never leave the machine by design (`/notion-sync` syncs filenames only; nothing uploads document content anywhere).
- **Personal data boundaries**: the tracker, salary data, and application archive are gitignored; documents never leave the machine by design (`/sync-twenty` syncs pipeline metadata and filenames only; nothing uploads document content anywhere). This fork deliberately tracks `documents/` source files in git.
Instruction-level defenses raise the bar; they are not a sandbox. If you run this workflow against job boards you do not trust at all, review what the agent fetched and wrote before sending anything out.
+2
View File
@@ -0,0 +1,2 @@
Id,Name,Domain Name / Link URL,Domain Name / Link Label,Domain Name / Secondary Links,Created by / Source,Created by / Workspace Member,Created by / Name,Created by / Context,Linkedin / Link URL,Linkedin / Link Label,Linkedin / Secondary Links,Last contact,Last contact item
c1a81b56-fa94-4d03-967a-88da331f8228,Roivant,https://roivant.com,Roivant,[],AGENT,6fa482f3-cebd-4bfa-a096-d454697afc54,Prad Nukala,,https://www.linkedin.com/company/roivant,Roivant,[],,
1 Id Name Domain Name / Link URL Domain Name / Link Label Domain Name / Secondary Links Created by / Source Created by / Workspace Member Created by / Name Created by / Context Linkedin / Link URL Linkedin / Link Label Linkedin / Secondary Links Last contact Last contact item
2 c1a81b56-fa94-4d03-967a-88da331f8228 Roivant https://roivant.com Roivant [] AGENT 6fa482f3-cebd-4bfa-a096-d454697afc54 Prad Nukala https://www.linkedin.com/company/roivant Roivant []
+2
View File
@@ -0,0 +1,2 @@
Id,Title,Created by / Source,Created by / Workspace Member,Created by / Name,Created by / Context,Creation date,Last update
f31ecf3b-87d3-4e8a-a84b-b6f0f3f8c7e2,My First Dashboard,SYSTEM,,System,{},2026-08-15T19:49:14.993Z,2026-08-15T19:49:14.993Z
1 Id Title Created by / Source Created by / Workspace Member Created by / Name Created by / Context Creation date Last update
2 f31ecf3b-87d3-4e8a-a84b-b6f0f3f8c7e2 My First Dashboard SYSTEM System {} 2026-08-15T19:49:14.993Z 2026-08-15T19:49:14.993Z
+2
View File
@@ -0,0 +1,2 @@
Id,Title,Body / BlockNote,Body / Markdown,Created by / Source,Created by / Workspace Member,Created by / Name,Created by / Context,Creation date
3b92cb37-85a0-4515-955a-c73a50a733e6,,,,MANUAL,6fa482f3-cebd-4bfa-a096-d454697afc54,Prad Nukala,{},2026-08-26T15:34:28.802Z
1 Id Title Body / BlockNote Body / Markdown Created by / Source Created by / Workspace Member Created by / Name Created by / Context Creation date
2 3b92cb37-85a0-4515-955a-c73a50a733e6 MANUAL 6fa482f3-cebd-4bfa-a096-d454697afc54 Prad Nukala {} 2026-08-26T15:34:28.802Z
+2
View File
@@ -0,0 +1,2 @@
Id,Position,Salary / Amount,Salary / Currency,Created by / Source,Created by / Workspace Member,Created by / Name,Created by / Context,Deadline,Company Id,Point of Contact Id,Last contact item,Last contact,Score,URL / Link URL,URL / Link Label,URL / Secondary Links,Verdict,Location / Address 1,Location / Address 2,Location / City,Location / State,Location / Country,Location / Post Code,Location / Latitude,Location / Longitude
f4d006dc-7cb0-4649-a3ca-732bb1e89961,Founding Engineer — Stackbirds,0,,AGENT,6fa482f3-cebd-4bfa-a096-d454697afc54,Prad Nukala,,,d214fab2-accf-4b29-98c3-09c051ae6e61,,,,70,https://www.linkedin.com/jobs/view/founding-engineer-at-stackbirds-4455351694,Founding Engineer,[],GOOD_FIT,,,San Francisco,CA,,,,
1 Id Position Salary / Amount Salary / Currency Created by / Source Created by / Workspace Member Created by / Name Created by / Context Deadline Company Id Point of Contact Id Last contact item Last contact Score URL / Link URL URL / Link Label URL / Secondary Links Verdict Location / Address 1 Location / Address 2 Location / City Location / State Location / Country Location / Post Code Location / Latitude Location / Longitude
2 f4d006dc-7cb0-4649-a3ca-732bb1e89961 Founding Engineer — Stackbirds 0 AGENT 6fa482f3-cebd-4bfa-a096-d454697afc54 Prad Nukala d214fab2-accf-4b29-98c3-09c051ae6e61 70 https://www.linkedin.com/jobs/view/founding-engineer-at-stackbirds-4455351694 Founding Engineer [] GOOD_FIT San Francisco CA
+2
View File
@@ -0,0 +1,2 @@
Id,Name / First Name,Name / Last Name,Emails / Primary Email,Emails / Additional Emails,Created by / Source,Created by / Workspace Member,Created by / Name,Created by / Context,Company Id,Phones / Primary Phone Number,Phones / Primary Phone Country Code,Phones / Primary Phone Calling Code,Phones / Additional Phones,Creation date,Job Title,Linkedin / Link URL,Linkedin / Link Label,Linkedin / Secondary Links,Last inbound,Last contact,Last meeting Id,Last contact item,Last contact by Id,Last outbound,Last email Id
7a93d1e5-3f74-4945-8a65-d7f996083f72,Ivan,Zhao,zhao@notion.com,[],SYSTEM,,System,,06290608-8bf0-4806-99ae-a715a6a93fad,882261739,,‍+1,[],2026-08-15T19:49:14.993Z,,,,[],,,,,,,
1 Id Name / First Name Name / Last Name Emails / Primary Email Emails / Additional Emails Created by / Source Created by / Workspace Member Created by / Name Created by / Context Company Id Phones / Primary Phone Number Phones / Primary Phone Country Code Phones / Primary Phone Calling Code Phones / Additional Phones Creation date Job Title Linkedin / Link URL Linkedin / Link Label Linkedin / Secondary Links Last inbound Last contact Last meeting Id Last contact item Last contact by Id Last outbound Last email Id
2 7a93d1e5-3f74-4945-8a65-d7f996083f72 Ivan Zhao zhao@notion.com [] SYSTEM System 06290608-8bf0-4806-99ae-a715a6a93fad 882261739 ‍+1 [] 2026-08-15T19:49:14.993Z []
+2
View File
@@ -0,0 +1,2 @@
Id,Title,Status,Created by / Source,Created by / Workspace Member,Created by / Name,Created by / Context,Due Date,Assignee Id,Body / BlockNote,Body / Markdown,Creation date
68892d48-7f2c-49c5-a399-36e255301b21,,TODO,MANUAL,6fa482f3-cebd-4bfa-a096-d454697afc54,Prad Nukala,{},,,,,2026-08-26T15:34:41.441Z
1 Id Title Status Created by / Source Created by / Workspace Member Created by / Name Created by / Context Due Date Assignee Id Body / BlockNote Body / Markdown Creation date
2 68892d48-7f2c-49c5-a399-36e255301b21 TODO MANUAL 6fa482f3-cebd-4bfa-a096-d454697afc54 Prad Nukala {} 2026-08-26T15:34:41.441Z
+2
View File
@@ -0,0 +1,2 @@
Id,Name,Statuses,Last update,Created by / Source,Created by / Workspace Member,Created by / Name,Created by / Context
33bfd30b-5558-53a8-866c-b679ce0c0bf9,Create company when adding a new person,"[""ACTIVE""]",2026-08-15T19:49:14.993Z,SYSTEM,,System,{}
1 Id Name Statuses Last update Created by / Source Created by / Workspace Member Created by / Name Created by / Context
2 33bfd30b-5558-53a8-866c-b679ce0c0bf9 Create company when adding a new person ["ACTIVE"] 2026-08-15T19:49:14.993Z SYSTEM System {}