SevyDevy

Guide · Interview prep

Take-Home Assignments: Scope, README, Tests and When to Decline

25 min readUpdated By Saket Bhatnagar

Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.

In short

  • Take-home assignments are coding tasks you finish alone and hand in as a repository, a project folder tracked by Git, a tool that saves every version. Companies that publish criteria check that it works, how you proved it, and how clearly you explain it.
  • Scope to the time box, which is the number of hours the company asks you to spend. Build the stated requirements first, each with a test, then stop and write down what you skipped.
  • The README is the text file that opens on a repository's front page. In a take-home, it is your voice: how to run the code and tests, what you assumed, and what you left out.
  • Red flags: unpaid work that runs into days, no time box for a big task, or a brief that seems lifted from their backlog, the work their team has queued. Ask first, and decline politely if the answers never come.
  • Beginners can stop after the pre-submit checklist. Engineers then get a tested script that copies your repository into an empty folder and runs its tests. They also see why a deleted secrets file stays in Git history, and how to defend the work.

What goes wrong when you treat a take-home like a hackathon?

You run out of time with half the requirements working, no tests and a one-line README. The reviewer cannot run your code, so the clever parts never get seen. A hackathon, a contest to build something flashy fast, rewards features; a take-home rewards the opposite.

Take-home assignments are judged on different signals from a live coding round. Nobody watches you think, so the repository has to show your thinking for you. It is read later, by someone you may never meet.

Picture a common setup. A final-year student gets an email with a brief. It asks for a command-line tool, a program run by typing a command, that reads a CSV file of shared expenses and prints each person's total per month. The setup is made up, but it mirrors the kind of task hiring pages describe.

A CSV file is a plain text table where commas separate the columns. The email suggests four hours and gives five days to submit a Git link. Some rows in the sample file are deliberately broken.

On the first evening the student adds a web page and charts, because those feel impressive. On the last night the monthly totals are still wrong for a broken row. There are no tests, and the README says only the project name.

Nothing in that story is about skill. It is about scope, proof and explanation, and those three can be learnt. This guide follows the same expense task from the brief to the follow-up interview.

Which words do you need before starting take-home assignments?

You need seven words. Each one is tied to the expense task.

  • Brief: the task description the company sends. Ours asks for monthly totals per person from a CSV file.
  • Time box: the hours you are asked to spend, such as four. It is different from the deadline, which is the date you must submit by.
  • Requirement: one thing the brief says the tool must do. A must-have is a requirement stated plainly; a nice-to-have is something you invented.
  • Repository: the project folder tracked by Git, a tool that records every saved version, called a commit. You usually submit a link to it.
  • Automated test: a small piece of code that runs your code and checks the answer, so anyone can repeat the check with one command.
  • README: the text file shown on the repository's front page. It explains how to run the work and why you built it this way.
  • Follow-up interview: a live call after the take-home where engineers ask about your choices or ask you to extend the code.

What are take home assignments and how are reviewers told to judge them?

Take home assignments are small, realistic tasks you complete alone and submit for an engineer to review later. Where companies publish their criteria, four signals keep coming back: it works, you proved it works, it is easy to read, and you explained your choices.

We read five companies' own hiring pages and blog posts on 27 October 2026. We did not use surveys or third-party lists, because their numbers cannot be checked against the companies' own words.

A pull request is a proposed set of changes that a reviewer can comment on line by line. Idiomatic means written the way people who use that language and library normally write it.

What five companies publicly say about their take-home or paid work task, checked on each company's own page on 27 October 2026. Processes change, so read the current page before you apply.
Company and pageFormat and time, as publishedWhat they say they look atPaid?
GitHub, engineering blog post of 31 March 2022A pull request on a copied repository, with clear instructions and a time limit. The length is not stated.Automated tests that give the reviewer a base level, then a reviewer scorecard on the pull requestNot stated
Tines, blog post of 17 June 2021; the page says the process changed in February 2022A small command-line version of their product, then a live session adding to itEvery stated requirement met, code that can be understood quickly, automated tests, run instructions, simple logicNot stated
Narrative, engineering hiring pageCompletable in under 4 to 6 hours, in the tools you chooseSolves the problem and passes their tests, how you gained confidence, idiomatic structure, choices and limitations explainedNot stated
Automattic, how they hire developersNear-real-world code, about a week allowed, time-boxedSecurity, performance, problem solving, communication, working in an unfamiliar codebaseChallenge not stated; the later trial is paid, about 15 to 35 hours
PostHog, engineering hiring handbookA paid full day, with a task deliberately too big for one dayPrioritising and shipping, code quality, product sense, communication, explaining your solutionYes, 1,000 US dollars for the day

Some lines are worth reading in the companies' own words. Tines says it values code that can be understood quickly over code that can be written quickly. It also asks for instructions on how to run the program and its tests.

Narrative asks how you gained confidence that your submission worked. It also asks whether you called out issues you did not address in the interest of time. That is a direct invitation to write a limitations section.

PostHog is the bluntest. Its handbook says that if a candidate cannot explain and defend their solution, it does not matter how polished it looks.

Put together, the five pages reward a working core first, then visible proof, readable code and honest notes. PostHog also rewards going beyond the basic requirements, but only after a working core ships.

How do you scope a take-home to the time box?

List every requirement in the brief and build those first, with a test each. Keep roughly the last third of the time for edge cases, the README and a final check. Edge cases are unusual inputs, such as a broken row or an empty file. Anything else goes into a "with more time" list.

The naive plan is to start with the most interesting part. For the expense task, that is the web page and charts. It is wrong because nothing in the brief asked for them, and every hour spent there comes out of tests and the README.

Tines names this mistake directly. Its post warns against candidates adding their own requirements, which it says costs time and makes the code more complicated.

An everyday picture helps. A take-home is like a board exam paper with compulsory questions and an optional bonus question.

  • Compulsory questions are the brief's stated requirements. Missing one costs more than any bonus can earn back.
  • Showing your working is your tests. The examiner, here the reviewer, wants to see how you got the answer.
  • The bonus question is a nice-to-have. Attempt it only after every compulsory answer is written and checked.
  • Where the picture breaks: in an exam, an unanswered question earns nothing. In a take-home, a clear note saying what you skipped and why still earns credit.

Turn the brief into a must-have list

  1. Read the brief twice

    First for the goal, then with a pen. Underline every verb the tool must do, such as read, total, print and skip.

  2. Write the must-have list

    For the expense task: read the CSV file, total by person and month, print the totals, and handle broken rows without crashing.

  3. Mark your assumptions

    The brief may not say what a broken row is. Decide, for example, that a row with a missing or non-numeric amount is skipped and reported.

  4. Send questions early

    Email any real ambiguity on day one. If no answer comes in time, keep your assumption and write it in the README.

  5. Fix the time box

    If the brief gives none, choose one yourself, such as four hours, and say so in the README.

Some tasks are too big on purpose. PostHog's handbook says its paid day uses a task designed to be too much for one person in a day, to see how candidates prioritise. Finishing everything is not the test there; choosing well is.

A four-hour plan you can copy

A suggested plan for a four-hour time box. It is our advice, not any company's rule. Scale each block to your own time box.
BlockTimeWhat you doDone when
Read and plan0:00 to 0:20Read the brief twice, write the must-have list, send questionsThe must-have list sits in a README draft
Skeleton0:20 to 0:40Set up the project, write one passing test, make the first commitThe test command prints 1 passed
Core requirements0:40 to 2:30Build each must-have with its own test, committing as you goEvery must-have has a passing test
Edge cases2:30 to 3:10Broken rows, empty files, clear error messagesThe sample file with broken rows runs without a crash
README3:10 to 3:40Run steps, assumptions, limitations, what you would do nextA stranger could run it from the README alone
Final check3:40 to 4:00Fresh clone, install, run the tests, then submitEvery step on the pre-submit checklist passes

Notice that building the core features gets under half the time. That can feel wrong at first, but the other blocks are what turn working code into a submission a reviewer can trust.

How do tests show reviewers your take-home works?

A test turns "trust me, it works" into one command the reviewer can run. GitHub's post says its automated tests give the reviewer a base level, and Tines says it expects automated tests in solutions.

Here is a small but complete solution to the expense task. We ran it, and the tests below, with Python 3.13.17 and pytest 9.1.1, the newest pytest release as of 27 October 2026. Pytest is a Python testing tool.

python
import csv
import sys
from collections import defaultdict
from decimal import Decimal, InvalidOperation


def monthly_totals(rows):
    """Return {(person, 'YYYY-MM'): total} and a list of skipped line numbers."""
    totals = defaultdict(Decimal)
    skipped = []
    for line_no, row in enumerate(rows, start=2):  # line 1 is the header
        try:
            person, month = row["person"], row["date"][:7]
            amount = Decimal(row["amount"])
        except (KeyError, TypeError, InvalidOperation):
            skipped.append(line_no)
            continue
        totals[(person, month)] += amount
    return dict(totals), skipped


def main(path):
    with open(path, newline="", encoding="utf-8") as f:
        totals, skipped = monthly_totals(csv.DictReader(f))
    for (person, month), amount in sorted(totals.items()):
        print(month, person.ljust(10), str(amount).rjust(10))
    if skipped:
        print(f"Skipped bad lines: {skipped}", file=sys.stderr)


if __name__ == "__main__":
    main(sys.argv[1])

Decimal is Python's exact decimal number type. It avoids the tiny rounding errors of ordinary floating-point numbers: in our run, 1.1 + 2.2 printed 3.3000000000000003 as a float and 3.3 as Decimal. The try block skips any row whose amount is missing or not a number, or whose person or date is missing, and records its line number.

Now the tests. Each test name says what it proves, so the test list reads like a specification.

python
from decimal import Decimal

from summarise import monthly_totals


def test_adds_amounts_per_person_per_month():
    rows = [
        {"date": "2026-10-03", "person": "user_a", "amount": "120.50"},
        {"date": "2026-10-19", "person": "user_a", "amount": "79.50"},
        {"date": "2026-11-01", "person": "user_a", "amount": "10"},
    ]
    totals, skipped = monthly_totals(rows)
    assert totals[("user_a", "2026-10")] == Decimal("200.00")
    assert totals[("user_a", "2026-11")] == Decimal("10")
    assert skipped == []


def test_bad_amount_is_skipped_not_fatal():
    rows = [
        {"date": "2026-10-03", "person": "user_b", "amount": "abc"},
        {"date": "2026-10-04", "person": "user_b", "amount": "50"},
    ]
    totals, skipped = monthly_totals(rows)
    assert totals == {("user_b", "2026-10"): Decimal("50")}
    assert skipped == [2]


def test_empty_input_gives_empty_result():
    assert monthly_totals([]) == ({}, [])


def test_short_row_leaves_no_zero_total():
    rows = [{"date": "2026-10-01", "person": "user_a", "amount": None}]
    totals, skipped = monthly_totals(rows)
    assert totals == {}
    assert skipped == [2]

The bug the tests caught

Our first version was shorter. It added the amount into the totals dictionary in a single line, inside the try block. The fourth test, about a short row, was written afterwards.

Pause and predict: a row has a person and a date but no amount. The conversion fails and the row is skipped. Can that row still change the output?

It did. The first version printed a total of 0 for that person and month, because looking up a missing key in a defaultdict creates it before the amount is converted. A defaultdict is a Python dictionary that fills in a default value, here zero, for missing keys.

The test failed with "Left contains 1 more item" and showed the stray zero total. The fix converts the amount first and only then touches the dictionary, which is the version shown above.

What just happened? A reviewer reading the old code could easily miss this. A test found it in seconds, and the test now proves the fix. That is the confidence Narrative asks candidates to show.

The sample file the brief supplies has a header and four data rows. Line 4 holds the broken amount.

text
date,person,amount
2026-10-03,user_a,120.50
2026-10-19,user_a,79.50
2026-10-04,user_b,abc
2026-10-05,user_b,50

Keep the tests about behaviour the brief cares about. Four sharp tests on the must-haves beat twenty tests on helper functions nobody asked about.

What should a take-home README include?

A take-home README should let a stranger run your code and tests in a few minutes, then explain what you assumed, what you chose and what you left out. Think of it as the cover letter for the code.

GitHub's own docs say a README typically tells people what the project does, why it is useful and how to get started. A take-home README needs those, plus the parts reviewers ask about.

A README skeleton, described section by section

  1. Title and one-line summary

    Name the tool and say what it does in one sentence: reads an expenses CSV and prints each person's total per month.

  2. How to run it

    Exact commands, the language version you used and any setup. For ours: Python 3.13, install from requirements.txt, then run summarise.py with the CSV path.

  3. How to run the tests

    The single test command and what a passing run looks like, such as 4 passed.

  4. Assumptions

    What the brief left open and what you decided. For ours: a row with a missing or non-numeric amount is skipped and reported, not fatal.

  5. Design choices and trade-offs

    Two or three choices with the reason, such as Decimal for money instead of floating-point numbers, and reading the file row by row.

  6. Known limitations

    What still breaks, stated plainly. These should come from your own testing, not guesses.

  7. With more time

    The nice-to-haves you skipped, in priority order, so the reviewer sees you noticed them.

  8. Time spent and tool use

    Roughly how long you spent, and how you used outside help or AI tools if the brief allows them.

Our known limitations came from probing the code after the tests passed. An amount written as NaN, short for not a number, is accepted by Decimal and turns that month's total into NaN. An amount written as 1,200 with a comma is skipped.

A blank or malformed date, such as oops, is not checked and becomes its own month. Line numbers also assume no field holds a line break inside quotes. Writing these four lines costs two minutes. It answers Narrative's question about known issues before the reviewer asks it.

How a reviewer meets your submission

Notice that the README comes before the code. If the run step fails, a reviewer may never reach your best work. This order is our working model of a typical review, not any one company's published process.

Diagram connections:

  • Your repository link to README (opens front page)
  • README to Install and run tests (follows run steps)
  • Install and run tests to Read the code (tests pass)
  • Read the code to Compare with the brief (checks requirements)
  • Compare with the brief to Scorecard or notes (writes verdict)
  • Scorecard or notes to Follow-up interview (invites to discuss)
  • Your repository link: Candidate → reviewer
  • README: Reviewer reads run steps first
  • Install and run tests: Reviewer → your test command
  • Read the code: Names, structure, simplicity
  • Compare with the brief: Every requirement met?
  • Scorecard or notes: Reviewer → hiring team
  • Follow-up interview: Hiring team → candidate

What should you check before you submit a take-home?

Check that a stranger can clone, install, test and run your work from the README alone, and that nothing private is in the repository. Run these steps in order, in the last block of your time box.

  1. Re-read the brief

    Tick every must-have against your code. Tines' post calls it critical that a solution meets each clear requirement.

  2. Run the formatter

    Use your language's standard formatter, a tool that lays out code in one consistent style. Tines notes that consistent formatting matters more than which formatting rules you pick.

  3. Read it as a reviewer

    Take a break, then read the code as if a teammate wrote it. Rename vague names like data or s, and delete comments that only repeat the code.

  4. Check the commit history

    Small commits with clear messages, such as add monthly totals with tests, show how you worked. PostHog's guide says it reviews git history for exactly this. Remove debug prints.

  5. Check for secrets

    No .env file, which is a file of private settings such as API keys, the passwords programs use to call online services, and no keys or passwords anywhere in history.

  6. Do a fresh clone

    Clone the repository into a new empty folder and follow your README word for word. Fix the README, not your memory, when a step fails.

  7. Submit and confirm

    Send the link before the deadline, check that the reviewer can open it, and reply on the same email thread.

Beginners can stop here: you can scope, test, explain and check a take-home. The rest covers a script that runs the fresh-clone check for you, how secrets leak through Git history, when to decline, AI tool rules and the follow-up interview.

How do you run a fresh-clone check before submitting a take-home?

Clone your own repository into a temporary folder, install from scratch and run the tests there. This catches the classic failure where code works only because of a file or package sitting on your laptop.

We wrote this script for the expense task and ran it with bash on Linux, git 2.43.0 and Python 3.13.17. It takes your repository's path or link as its only input. It assumes a Python project with requirements.txt and pytest, like ours; change the last three lines for your stack.

bash
#!/usr/bin/env bash
# Pre-submit check: clone the repo fresh, install, run the tests, look for secret file names.
# Usage: bash presubmit_check.sh REPO_PATH_OR_URL
set -euo pipefail
REPO="$1"
WORK="$(mktemp -d)"
git clone --quiet "$REPO" "$WORK/repo"
cd "$WORK/repo"
echo "== Files Git will ship =="
git ls-files
echo "== Env or key file names anywhere in history (names only, not contents) =="
git log --all --name-only --pretty=format: | sort -u | grep -Ei '(^|/)\.env|\.pem$|id_rsa' || echo "none found"
echo "== Fresh install and tests =="
python3 -m venv .venv
.venv/bin/pip install --quiet -r requirements.txt
.venv/bin/python -m pytest -q

Read it in parts. git clone, which copies a repository, makes a clean copy, so files you never committed are absent. git ls-files lists exactly what the reviewer will receive.

The git log line lists the file names touched by every commit on every branch, then searches for .env files, .pem key files and id_rsa keys. It checks file names, not file contents, so still read your changes for keys pasted into code. The last three lines build a fresh virtual environment, an isolated Python install, and run the tests.

On our clean repository it printed the six shipped files, then "none found", then 4 passed. On a copy where we had committed a fake .env file and deleted it in the next commit, the file list looked clean. The history search still printed .env.

Why does deleting a secrets file not remove it from Git history?

Because every commit is a saved snapshot. Deleting a file in a new commit only removes it from later snapshots, and the old commit still holds the file for anyone with the repository.

We tested this with git 2.43.0 and a fake value. After committing a .env file and deleting it in the next commit, git ls-files no longer listed it. One command still printed it back.

bash
git rm -q .env; git commit -qm "c2 deletes .env"
git ls-files            # .env is no longer listed
git show HEAD~1:.env    # prints API_KEY=FAKE-EXAMPLE-VALUE

A second trap: adding a file to .gitignore does not stop Git tracking it if it was already committed. The gitignore docs say files already tracked by Git are not affected.

In our run, the .env file was still tracked and showed as modified after we ignored it. Running git rm --cached on it stopped the tracking and left the file on disk.

If a real key ever reached a pushed commit, GitHub's docs say the first step is to revoke or rotate it, meaning cancel the key and issue a new one. They also warn that you cannot remove data from other people's clones.

Which red flags mean you should decline a take-home?

Push back, or decline, when the work is open-ended and unpaid, has no time box, or looks like their real product backlog. Ask first, because many problems are fixed by one clear answer.

The published pages give a useful yardstick. Narrative asks for under 4 to 6 hours and says it does not want candidates to give away days of free work. Automattic pays for its later trial project, and PostHog pays for its full-day task.

The list below is our advice, not data. Weigh it against how much you want the role.

  • No time box for a task that is clearly several days of work, and no answer when you ask how long to spend.
  • A brief that reads like a real ticket, a work item from their team's tracker: their production data (real customer data), their codebase, or a missing feature.
  • Unpaid work expected to run past a full day, especially before you have spoken to any person at the company.
  • A requirement to deploy it, meaning put it live on a server, on your own paid cloud account, or to hand over rights to the code.
  • No stated criteria, and no answer when you ask what reviewers look for.
  • A take-home on top of a long series of live coding rounds that already tested the same skills.

Should you take this take-home?

Notice that most paths lead to asking, not to declining. Declining comes only after a clear question gets no clear answer.

Diagram connections:

  • Brief arrives to Time box stated? (read the brief)
  • Time box stated? to Under a day, or paid? (Yes)
  • Time box stated? to Ask one clear email (No: ask for one)
  • Under a day, or paid? to Looks like their backlog? (Yes)
  • Under a day, or paid? to Ask one clear email (No: ask for less)
  • Looks like their backlog? to Do it to the time box (No)
  • Looks like their backlog? to Ask one clear email (Yes: ask how it is used)
  • Ask one clear email to Clear answer back? (wait)
  • Clear answer back? to Do it to the time box (Yes)
  • Clear answer back? to Decline politely (No)
  • Brief arrives: Company → you
  • Time box stated?: Hours, not just a deadline
  • Under a day, or paid?: Compare effort with reward
  • Looks like their backlog?: Real data, real feature
  • Ask one clear email: You → recruiter
  • Clear answer back?: Within a few working days
  • Do it to the time box: Must-haves, tests, README
  • Decline politely: Offer an alternative

How to decline without burning the bridge

  1. Thank them

    Thank the recruiter for the time they have spent on your application so far.

  2. Give a short reason

    Say the time needed does not fit your current commitments. You do not need to criticise the task.

  3. Offer an alternative

    Offer a live pairing round, where you code with an engineer while talking it through. Or offer a shorter task, or a walk-through of past work.

  4. Leave the door open

    Say you would be glad to continue if the format can change. Keep it to five or six lines.

Some recruiters can change the format when asked. If they cannot, you have still saved a weekend for an application that values your time.

Can you use AI tools on a take-home assignment in 2026?

Only if the brief allows it, and then you must be able to explain every line. Rules can differ even between stages at one company.

PostHog's handbook, as of 27 October 2026, allows AI tools in its paid project day but not in its debugging session. The same page says candidates must understand and be able to explain what they built.

If the brief says nothing, ask the recruiter in writing. If tools are allowed, say in the README how you used them, such as generating test data or a first draft of a function you then rewrote.

The follow-up interview is where this matters. Engineers will ask why a line exists, and an answer of "the tool wrote it" can undo the whole submission.

How do you walk through your take-home in the follow-up or system design interview?

Restate the problem, show the shape of your solution, name your trade-offs, and then answer the "what if it were bigger?" question. Narrative's page says its follow-up covers design choices, deployment and hypothetical changes to the problem. System design means planning how the parts of a bigger system fit and scale.

  1. Restate the problem

    One sentence: read an expenses CSV, total per person per month, skip broken rows, in a four-hour time box.

  2. Show the shape

    One file reads rows, one function totals them, the output is sorted. Point to where each must-have lives.

  3. Name two trade-offs

    Decimal over floating point for money. Skip and report broken rows instead of stopping, because one bad row should not hide good data.

  4. Show your proof

    Run the tests live. Tell the short-row story: the test caught a stray zero total that reading the code could have missed.

  5. Scale it

    For a file of 10 crore (100 million) rows, the CSV reader already reads row by row. Memory grows with person-month pairs and skipped lines, not total rows, so the next limit is that dictionary.

  6. Say what comes next

    With more time: reject NaN amounts, check dates, accept amounts with commas, and add one test that runs the whole tool on the sample file.

Questions people ask

How long should a take-home assignment take?
As long as the brief's time box says, and no more. Published examples vary: Narrative asks for under 4 to 6 hours, while PostHog pays for a full day. If the brief gives only a deadline, ask how many hours they expect. If nobody answers, choose a time box yourself, state it in the README and stop when it ends.
Is it okay to go over the time limit on a take-home?
A small overrun to finish the README is usually better than a submission nobody can run. Do not keep building features, though. Some companies time it: GitHub's post says a timer starts when the candidate gets access to the repository. Write how long you actually spent, and list unfinished work under a with-more-time heading.
Should I add extra features to make my take-home stand out?
No, finish and prove the stated requirements first. Tines' post warns that candidates who add their own requirements spend time and make the code more complicated. PostHog's paid day does reward improvements beyond the basic requirements, but its guide says strong candidates ship a working core feature early first. If you have time left, improve tests, error messages and the README, then list feature ideas in the README instead of building them.
Do I need tests if the take-home brief does not ask for them?
Yes, a few focused tests are worth it. Tines says it expects automated tests, and Narrative asks how you gained confidence that your submission worked. Tests also protect you: in our expense example, a test caught a stray zero total that reading the code missed. Cover each must-have and the broken-input cases the brief mentions.
Can a company use my take-home code in its product?
That depends on the terms you agree to, and we cannot give legal advice. If the brief uses their real codebase, real data or a feature their product lacks, ask in writing how the work will be used. If the answer is unclear, treat it as a red flag and either decline or ask for a paid trial instead.
What should I do if I pushed a secret key in my take-home repository?
Revoke or rotate the key first, meaning cancel it and issue a new one. GitHub's docs give this as the first step and warn that other people's clones keep the old data. Deleting the file in a new commit is not enough: in our test, git show still printed it from the earlier commit. Then clean the history before you resubmit.
How do I decline a take-home assignment politely?
Send a short, warm email. Thank the recruiter and say the time needed does not fit your commitments. Offer an alternative, such as a live pairing round, a shorter task or a walk-through of past work. Avoid criticising the task. Some recruiters can adjust the format, and a polite no keeps the door open for later roles.

Sources and further reading

Practise this with Lala

Start