Turn a list of leads into comments and emails that are ready to review. Nudgeline drafts a natural comment for a lead's post and a personalised email for the lead. You read, edit and approve everything, then post or send it yourself.
- What it does
- How it works
- A look at the app
- Requirements
- Quick start
- Using the web app, step by step
- Your input file
- Email templates
- Command line
- Output
- Project layout
- Sending responsibly
- Privacy
- License
- Troubleshooting
You bring a list of leads: each row has a post, a business name, an owner name and an email. For every row Nudgeline writes:
- a comment to reply to their post, short and specific to what they wrote, and
- a personalised email with a subject and body that refer to that same post.
Then it hands the drafts to you. Nothing is ever posted or sent by the tool. There is no auto-send, no scraping and no bot account.
| Guided web app | Upload, customise, generate, review, export. Opens in your browser. |
| Quick comment | Paste a single post and get one comment to copy. No file needed. |
| Human review step | Every draft is a suggestion until you press Approve. Only approved drafts can be exported. |
| Your voice | Pick a tone (friendly, professional, casual) or use your own email template. |
| Comment length | Choose a short comment, a longer one, or both at once and pick the one that fits the post. |
| Skips what does not fit | Posts that are not a real need for your service are marked as skipped instead of getting a forced reply. |
| Automatic checks | Drafts that look risky or off are flagged for a closer look before you approve. |
| Language aware | Replies in the language of the post, including Roman Urdu. |
| Safe to stop and resume | Command line runs save progress as they go. Run the same command again and it continues, retrying rows that failed. |
| Bring your own AI key | Works with Groq, Grok (xAI) or Claude. You use your own account. |
| Runs on your computer | Your lead data stays on your machine. |
flowchart LR
A["Leads file<br/>CSV, Excel or JSON"] --> B["Read the file and<br/>match the columns"]
P["One pasted post<br/>(Quick comment)"] --> C
B --> C{"Is this a real need<br/>for your service?"}
C -- No --> S["Marked as skipped"]
C -- Yes --> D["AI drafts a comment<br/>and a personalised email"]
D --> E["Automatic checks<br/>flag anything risky"]
E --> F["You review in the browser<br/>edit, approve or reject"]
F --> G["Export approved drafts<br/>as a CSV"]
G --> H["You post or send<br/>each message yourself"]
Every draft ends up in one of these states:
stateDiagram-v2
state "Ready" as Ready
state "Check this" as Check
state "Not a fit" as Skipped
[*] --> Ready
[*] --> Check: a check found something
[*] --> Skipped: not a real need
Ready --> Approved: you approve
Check --> Approved: you edit, then approve
Ready --> Rejected: you reject
Check --> Rejected: you reject
Approved --> Exported: export CSV
Exported --> [*]
And at a high level the pieces fit together like this:
flowchart LR
UI["Browser<br/>(guided web app)"] <--> APP["Local app<br/>127.0.0.1"]
APP --> PIPE["Drafting pipeline<br/>comments and emails"]
PIPE --> AI["Your AI provider<br/>(your own API key)"]
PIPE --> FILES[("CSV files<br/>on your computer")]
Drop a CSV, Excel or JSON file. Nudgeline matches your column names automatically and shows what it understood before you run anything. No file handy? Try the built-in samples.
Your name, the service you offer, one line about you, the tone, the comment length (short, longer or both), and how many leads to do this time. Optionally add your own email template.
A clean summary first, then a list of leads with a detail panel. Read each draft, edit it, and approve or reject. Drafts that need a closer look are marked Check this.
Dark mode is supported too:
Use Quick comment: paste a post, press Write comment, copy the result.
Screenshots use made-up sample leads.
| What | Details |
|---|---|
| Python | 3.10 or newer (developed and tested on 3.12) |
| Operating system | Windows, macOS or Linux (developed on Windows) |
| An AI API key | One of: Groq (gsk_...), xAI Grok (xai-...), or Anthropic Claude (sk-ant-...) |
| A web browser | Any modern browser, for the local web app |
| Python packages | openai, anthropic, httpx, openpyxl (installed from requirements.txt) |
| Internet | Only for the calls to your AI provider |
No database, no Docker and no browser automation are needed.
1. Get the code
git clone https://github.com/Hafsa-Anwar65/NudgeLine.git
cd NudgeLine2. Create a virtual environment (recommended) and install
Windows (PowerShell):
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -r requirements.txtmacOS / Linux:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt3. Add your AI key
copy .env.example .env # Windowscp .env.example .env # macOS / LinuxOpen .env and paste one key (the line for your provider). Never commit this file: it is already in .gitignore.
4. Start the app
python app.pyIt opens http://127.0.0.1:8000. Press Ctrl+C in the terminal to stop it.
- Open the app. Run
python app.pyand use the Start with demo button on the home page to see finished example drafts first, or go straight to the app. - Add your leads. Drop your file or click to choose it. Check the "Looks good" summary: it shows which of your columns were used for post, business, owner and email.
- Tell it about you. Fill in your name, the service you offer and one line about you. Pick a tone and a comment length.
- Choose how many leads. Start small (3 to 5) to see the style, then do the full list.
- (Optional) Use your own email template. Open the template section and use the placeholders described below.
- Generate drafts. Press the button and watch the progress bar. You can leave the page open while it works.
- Review. Use the summary tiles and filter tabs (Ready, Check this, Approved, Skipped / failed). Click a lead, read the drafts and edit them directly in the boxes. Changes save automatically.
- Approve or reject. Press Approve on each draft you are happy with, or Approve all ready for the ones with no warnings. Drafts marked Check this always need your own look first.
- Export. Press Export approved (CSV). Only approved drafts are included.
- Post or send yourself. Copy each comment or email and use it from your own accounts, in small batches.
CSV, Excel (.xlsx) or JSON. Column names are matched loosely, so your existing headers usually just work.
| Field | Accepted column names (examples) |
|---|---|
| Post | Post content, post_text, post, content, message, text |
| Business | Business Name, company, business, page_name |
| Owner | Owner Name, Client Name, name, owner, contact |
Email, email_address, owner_email |
|
| Website (optional) | website, site, url |
| Post link (optional) | post_url, link, permalink |
Example:
| Client Name | Business Name | Post content | |
|---|---|---|---|
| Amina Rafiq | Brew & Bean Cafe | Opening my cafe next month and need a website with a menu and online reservations. | amina@example.com |
Samples to try are in the sample/ folder (old_data.csv with 5 rows, more_samples.csv / more_samples.xlsx with 20 varied rows, including posts that are not leads and rows with a bad email).
Prefer your own wording? Paste a template and the AI only fills in the placeholders:
Subject: Quick idea for {company}
Hi {first_name},
{post_hook}
I build simple, fast websites for small businesses. Happy to share a few ideas if useful.
Best,
Your Name
| Placeholder | Filled with |
|---|---|
{first_name} |
The owner's first name |
{name} |
The owner's full name |
{company} |
The business name |
{post_hook} |
One sentence that refers to their post |
Leave the template empty to let the AI write each email from scratch.
The same drafting engine is available without the browser:
python main.py comments --input sample/posts.json
python main.py emails --input sample/leads.csv
python main.py both --input sample/more_samples.csv --limit 5
python main.py approve --input output/outreach.csv --interactive| Command | What it does |
|---|---|
comments |
Drafts comments for already-fetched posts (JSON or CSV) |
emails |
Drafts personalised emails from a CSV or a plain list of emails |
both |
One run, two drafts per row: a comment and an email (CSV, Excel or JSON) |
approve |
The review step for the command line: export only what you approve |
Handy options: --limit 5 (try a few first), --dry-run (test everything without calling the AI), --tone friendly|professional|casual, --template path.txt, --output path.csv. Running a command again resumes where it stopped.
Set your name, service and sign-off in profile.json.
The web app saves every run under output/ (this folder is ignored by git). Exports contain only the drafts you approved.
| Column | Meaning |
|---|---|
name, company, email |
The lead |
post_text |
Their post |
comment |
The drafted comment |
subject, body |
The drafted email |
priority, language |
How strongly the post asks for your service, and its language |
qa_flags |
Why a draft was marked Check this, if it was |
status |
draft, needs_edit, approved, rejected, skipped or error |
NudgeLine/
├── app.py # starts the local web app
├── main.py # command line entry point
├── profile.json # your name, service and sign-off
├── drafter/ # the drafting pipeline (comments, emails, review)
├── webui/ # the guided web app (HTML, CSS, JavaScript)
├── frontend/ # the home page
├── sample/ # example inputs to try
├── docs/screenshots/ # images used in this README
├── requirements.txt
└── .env.example # copy to .env and add your key
Nudgeline writes the first draft. You are responsible for what you send or post.
- Read every draft and make sure it is true and relevant to that person.
- Follow the rules of the platform where you comment, and the email rules that apply to you (for example CAN-SPAM, GDPR and local laws). Keep your opt-out line.
- Go slowly and in small batches. Do not mass-send.
- Only contact people who have publicly asked for what you offer.
- The app runs on your computer and listens on
127.0.0.1only. - Your files and drafts are stored in the local
output/folder. - The only data that leaves your machine is the text sent to your own AI provider to write the drafts, under your own API key.
.env(your key) andoutput/are excluded from git. Checkgit statusbefore you push.
Nudgeline is released under the Functional Source License, Version 1.1, MIT Future License (FSL-1.1-MIT), Copyright 2026 Hafsa Anwar.
In plain words: the code is open for you to read, run and learn from, but you cannot take it and sell a competing product.
| ✅ Use it for your own outreach, inside your own business | Allowed |
| ✅ Read, study and learn from the code | Allowed |
| ✅ Modify it and build your own tools on top for internal use | Allowed |
| ✅ Use it for teaching, school projects and non-commercial research | Allowed |
| ✅ Help a client run it as a professional service | Allowed |
| ✅ Fork it and contribute back | Allowed |
| ❌ Offer Nudgeline, or a close copy, to others as a paid product or hosted service | Not allowed (Competing Use) |
| ❌ Remove the copyright notice or the license text | Not allowed |
| ❌ Use the Nudgeline name or branding as your own | Not allowed |
Every version turns into plain MIT on the second anniversary of the day it was released. The license cannot be taken back. Today's code will be fully free to use for anything in 2028.
Is this open source? It is source-available. The code is public and you can use it freely, but the Competing Use limit means it does not meet the official open source definition until each version converts to MIT.
Can I use it at my company? Yes, for your own outreach and internal work. Selling it, or a hosted version of it, to others is the one thing that is off limits.
I want to build a product with it. Open an issue to talk about a commercial licence.
The full legal text is in LICENSE. If this summary and the license ever differ, the license is the one that counts.
| Problem | What to try |
|---|---|
No API key found |
Open .env and paste your key on the matching line, then restart python app.py. |
Model not found / 404 |
Your account may not have the default model. Set LLM_MODEL in .env to a model name from your provider's console. |
Port 8000 is busy |
Run python app.py --port 8001. |
| Drafts show "AI service is busy" | You reached your provider's rate limit. Wait a minute and run again, or try fewer leads. On the command line, running the same command again retries failed rows. |
| The page looks old after an update | Restart python app.py, then press Ctrl+F5 in the browser. |
| Excel file not read | Make sure the first row has headers and the file is .xlsx. |
Nudgeline is under active development. Made by Hafsa Anwar.





