How to pick which task to automate first

Most automation projects fail because the wrong task was chosen, not because the code was bad. Here is the arithmetic that says whether a task is worth scripting, a scoring table to run over your own week, what to leave alone, and two worked examples in Python.

Multiply how often a task happens in a year by how many minutes it takes. If the answer is under about 10 hours, do not automate it — you will spend longer building and maintaining the script than doing the job. That one calculation kills most automation ideas, including several that feel unbearably tedious. Tedium is not the signal; annual minutes and the cost of a mistake are. Below is how to run that arithmetic properly, a table for scoring your own week, and two examples that pass the test for different reasons.

The arithmetic

Annual minutes = times per year x minutes per run. Then compare that with the build cost, honestly stated in hours, and with what a mistake costs.

  • A 20-minute job, six days a week: 312 runs, 104 hours a year. Build it in eight hours and you are ahead by week five.
  • A 10-minute job, once a month: 2 hours a year. Six hours of building to save two hours a year is a hobby, not a project.
  • A 4-hour job, twice a year: 8 hours. Borderline on time, but if it is a GST reconciliation where a missed mismatch costs you a notice, the error cost decides it.

Error cost is the second axis and it overrides the first. Two categories qualify: money that leaves without being noticed (an unreconciled payment, a supplier paid twice) and deadlines with statutory consequences. A three-minute task done wrong once a quarter can justify a script that a two-hour task never would.

There is a third factor people forget: who does it now. If one person does a 30-minute daily job from memory, with unwritten exceptions, your real risk is that they are on leave in March. Automating it forces the exceptions into code where everyone can read them. That is worth real money and does not appear in the time saved.

What makes a task automatable

Three properties. Miss any one and the build takes three times as long as estimated.

The input arrives in a stable shape. Same columns, same file naming, same source. A CSV exported from the same portal every day is ideal. "A spreadsheet somebody emails, laid out differently each month" is the single most expensive input in existence, because you are not automating a task, you are writing a parser for human improvisation.

The rule is decidable without judgement. "Flag every invoice over Rs 50,000 without a PO number" is a rule. "Flag the ones that look odd" is a person.

Nothing blocks the machine. A login is fine if you hold the credentials. A captcha or an OTP is a wall, and getting around it usually breaks the portal's terms of use. Stop and ask the provider for an API or a scheduled export instead.

What not to automate

  • Anything under roughly 10 annual hours with no error cost attached.
  • Tasks whose input format changes every time. Fix the input first: one template, one export path. That fix is often the whole win.
  • Work that needs judgement. You can automate the gathering and leave the decision to a human — that split is usually the best design anyway.
  • One-off cleanups. A three-hour manual slog beats a two-day script you run once.
  • Anything behind a captcha or an OTP.
  • A process that is about to change. Automating a workflow two months before the accounting system is replaced is pure waste.
  • The step that is the control. If a manager reviews a payment list precisely because someone should look at it, automating the looking removes the control, not the work.

Score your own week

Write down every recurring task you or your staff did last week. Score each 1 to 5 on four axes and multiply the first two, then use the last two as brakes.

Axis 1 3 5
Annual hours under 5 20–50 over 100
Error cost annoying a day of rework money or a statutory deadline
Input stability different every time mostly consistent identical export every run
Judgement needed a person must decide rules with exceptions fully mechanical

Multiply all four. Above 100, build it. Between 40 and 100, build the smallest useful version. Below 40, leave it alone or fix the input first.

Applied to a typical week in a small firm:

Task Annual hrs Error cost Input Judgement Score Verdict
Merge 6 branch sales files daily, 20 min 5 3 5 5 375 Build it
Match bank credits to invoices, 45 min weekly 4 5 4 4 320 Build it
Split the master workbook per branch, 12 min daily 4 2 5 5 200 Build it
Chase overdue payments by phone 4 4 2 1 32 Automate the list only
Quarterly board deck 2 2 1 1 4 Leave alone
Reply to customer emails 5 3 1 1 15 Leave alone

Note the fourth row. The call is judgement, so it stays human, but generating the list of who to call is mechanical and takes ten minutes a day. Splitting a task in two like that is the most under-used move in small-business automation.

Worked example 1: the one that pays through error cost

Matching bank credits against issued invoices. Forty-five minutes a week is only 39 hours a year, but a payment silently credited to the wrong invoice is money you chase twice and a customer relationship you damage once.

import pandas as pd

bank = pd.read_csv("bank_statement.csv", encoding="utf-8-sig")
inv = pd.read_excel("invoices.xlsx", dtype={"invoice_no": str})

bank["ref"] = bank["narration"].str.extract(r"(INV[-/]?\d{3,6})", expand=False) \
                               .str.replace(r"[-/]", "", regex=True)
inv["ref"] = "INV" + inv["invoice_no"].str.zfill(4)

m = bank.merge(inv[["ref", "invoice_no", "amount", "party"]],
               on="ref", how="outer", indicator=True,
               suffixes=("_bank", "_inv"))

unmatched_credit = m[(m["_merge"] == "left_only") & (m["credit"] > 0)]
unpaid = m[m["_merge"] == "right_only"]
matched = m[m["_merge"] == "both"].copy()
matched["gap"] = (matched["credit"] - matched["amount"]).round(2)
short_paid = matched[matched["gap"].abs() > 1]

with pd.ExcelWriter("reconciliation.xlsx") as x:
    unmatched_credit.to_excel(x, "credit_no_invoice", index=False)
    unpaid.to_excel(x, "invoice_unpaid", index=False)
    short_paid.to_excel(x, "amount_mismatch", index=False)

print(f"{len(matched) - len(short_paid)} clean, {len(short_paid)} mismatched, "
      f"{len(unmatched_credit)} unexplained credits, {len(unpaid)} unpaid")

Two lines do the real work. indicator=True on an outer merge is the whole reconciliation: left_only is money with no invoice, right_only is an invoice with no money, both is a candidate match. And dtype={"invoice_no": str} stops pandas turning 0045 into 45, which is the classic way a reconciliation reports phantom mismatches.

The abs() > 1 tolerance matters in practice. Bank charges and rounding produce one-rupee gaps that are not errors, and a script that reports 400 rows of noise gets ignored within a fortnight. Note also what this script does not do: it does not mark anything as paid. It produces three lists for a person to act on, which is the right boundary.

Worked example 2: the one that pays through frequency

Splitting one master sheet into a file per branch. Twelve minutes a day, six days a week: 62 hours a year, no error cost worth mentioning, completely mechanical. It qualifies on volume alone.

from pathlib import Path
import re
import pandas as pd

OUT = Path("out") / pd.Timestamp.today().strftime("%Y-%m-%d")
OUT.mkdir(parents=True, exist_ok=True)

df = pd.read_excel("master.xlsx", dtype={"invoice_no": str})
df.columns = [c.strip().lower().replace(" ", "_") for c in df.columns]

if "branch" not in df.columns:
    raise SystemExit(f"no 'branch' column; found {list(df.columns)}")

blank = int(df["branch"].isna().sum())
for branch, part in df.dropna(subset=["branch"]).groupby("branch"):
    safe = re.sub(r"[^a-z0-9]+", "-", str(branch).lower()).strip("-")
    part.to_excel(OUT / f"{safe}.xlsx", index=False)

print(f"{df['branch'].nunique()} files in {OUT}, {blank} rows had no branch")

The column-normalising line is what keeps this alive past the first month, because somebody will eventually export the sheet with Branch and a trailing space. The explicit SystemExit when the column is missing is deliberate: a script that fails loudly on Tuesday is a small problem, and one that writes twelve empty files quietly is a large one. Printing the blank count means you find out that nine rows had no branch, instead of losing them.

Both examples are about 25 lines, which is normal. If your first automation needs 300 lines, you probably picked a task that failed the input-stability test.

What the score does not tell you

Build estimates are wrong in one direction. Double whatever you first think, and treat the extra as the cost of discovering that the June export has an extra header row.

Maintenance is real: budget an hour a month per script. Things break for four reasons: a renamed column, a moved folder, an expired password, an unattended reboot. A script nobody maintains is worse than the manual process, because people trust its output.

Write the folder paths and the recipients down somewhere that is not the code. In eight months you will not remember.

Once a task scores above 100, the scripts themselves are the easy part. Five of them (merging exports, emailing a PDF summary, filing scanned invoices, watching a folder, pulling a portal export), with scheduling, credentials and failure alerting, are in five Python jobs that save a small business a day a week. The language underneath them is covered in the Python track and the pandas track, and if you would rather have it built and monitored for you, that is our automation work.

Frequently asked questions

What is the smallest task worth automating? Roughly 10 hours a year, unless a mistake costs money or misses a statutory deadline. A daily 5-minute job clears that bar at 26 hours a year; a monthly 20-minute job does not, at 4 hours.

Should I automate the most annoying task first? No. Automate the highest-scoring one and check that its input is stable. The most annoying task is usually annoying precisely because it is irregular and full of exceptions, which makes it the hardest and least reliable to script.

Excel macros or Python? Macros are fine when the work stays inside one workbook and one person's PC. Choose Python when the job touches several files, PDFs, email, a website or a database, or when it has to run on a schedule with nobody logged in.

How do I know a script is still working? Make it write a log line and touch a last_run.txt on every success, then check that file. Silence is the dangerous failure mode: a report that stops arriving gets noticed three weeks later, after decisions have been made without it.

B

Written by Bablu Kumar Jha

Founder, BeeProton AI · Mumbai, Maharashtra, India

Related posts