Ghostwriter is one of those tools people either lean on constantly or quietly ignore, and the difference usually comes down to how they ask it for things. Installed and left alone, it finishes your brackets and suggests variable names. Used deliberately, it can write a working deduplication function, explain a 200-line file you inherited from a teammate who left, and spot the off-by-one error you’ve been staring at for twenty minutes.
This walkthrough is hands-on. We’ll build a small Python data-cleaning script, pushing Ghostwriter at each stage to show where it earns its keep, where it wastes your time, and what to type when it gets something wrong.
What Ghostwriter is actually doing while you type
Ghostwriter is Replit’s built-in AI coding assistant. It shows up in three places, and knowing which one to reach for saves a lot of fumbling:
- Inline autocomplete, the grey “ghost text” that appears as you type. Fast, low-commitment, great for boilerplate.
- The command palette, which includes Generate Code, Explain Code, Transform Code, and Debug. These act on a selection or a prompt.
- The chat panel, for back-and-forth where you refine an idea over several messages.
Under the hood it’s an AI coding assistant tuned on code, which means it’s strongest on patterns it has seen thousands of times and weakest on the specifics of your project. That asymmetry shapes everything below. If you want a broader sense of how these assistants behave as collaborators rather than autocomplete engines, it’s worth reading up on Replit Ghostwriter as a coding coworker before you start leaning on it.
Step 1: Give it context before you ask for anything
Ghostwriter reads what’s around your cursor, so a blank file with a vague prompt is the worst possible setup. Spend sixty seconds making the file legible first.
Open a fresh Python Repl, create clean_survey.py, and put a real comment at the top:
# Clean raw survey CSV exports: drop duplicate responses, normalise column names, output to cleaned.csv
Then do the boring structural work yourself: your imports at the top, function names that describe what they do, and a docstring stub above anything you intend to generate. A function signature plus a one-line docstring is the single highest-leverage thing you can hand an AI assistant. It turns “write some code” into “fill in this specific contract.”
Step 2: Let autocomplete handle the boring 30%
The inline suggestions are most useful for code you’d write identically every single time. Typing df = pd.read_csv( and watching the path and encoding='utf-8' appear? Accept it. Typing a loop header and getting the standard for i, row in enumerate(...) scaffold? Accept that too.
Where you should be sceptical is anything with business meaning. Autocomplete will happily invent a column called response_date that doesn’t exist in your CSV, and you won’t notice until runtime. A rough rule: accept suggestions for syntax and structure, review suggestions for logic and data.
One practical trick is to press Escape when a bad suggestion appears rather than typing through it. Ghostwriter learns from the local file context quickly, and rejecting a suggestion a few times tends to shift what it offers next.
Step 3: Use Generate Code with a spec, not a wish
Vague prompts produce vague code. Compare these two:
Weak: “make a script that cleans data”
Strong: “Write a Python function dedupe_rows(df, key_columns) that drops duplicate rows based on the given columns, keeps the first occurrence, prints how many rows were removed, and returns the cleaned DataFrame. Do not modify the input in place.”
The second prompt works because it covers four things in about thirty words:
- Signature: the exact name and arguments you want.
- Behaviour: what counts as a duplicate, and which row wins.
- Side effects: what it prints or writes.
- Constraints: the things a naive implementation would get wrong, like mutating the input.
That last category matters more than people expect. Adding “return a new DataFrame” or “raise a ValueError instead of returning None” heads off the exact shortcuts a model would otherwise take.
Step 4: Explain Code when you inherit something unreadable
Select a dense block, open the command palette, and choose Explain Code. A chained mess of groupby, apply, and a lambda that unpacks a tuple becomes a plain-English description in a few seconds, which is often all you needed to start editing it confidently.
The follow-up question is where the real value sits. After the initial explanation, ask the chat panel something like “which line would break if the input had a null in the region column?” That turns a summary into a targeted risk check. It’s a similar pattern to what you’d use in JetBrains AI Assistant within a JetBrains IDE, where explanation quality depends heavily on how specific your question is.
Step 5: Debug by pasting the traceback, not the whole file
Dumping an entire 400-line file into the debug prompt dilutes the signal. Paste three things instead: the error message and traceback, the function it points at, and the input that triggered it.
A realistic example. You run the dedupe function on a two-row CSV and get:
KeyError: "['resp_id'] not in index"
Paste that alongside the function and the header line of your CSV, and Ghostwriter will usually spot the whitespace in "resp_id " before you do. If it suggests a fix that adds a try/except to swallow the error, push back. Ask it to fix the cause, not the symptom, or you’ll end up with a script that silently drops rows.
Step 6: Transform Code for refactors and language swaps
Transform Code works on a selection and takes an instruction. Two things it’s genuinely good at:
- Style refactors: “Rewrite this loop as a dictionary comprehension.” “Replace
os.pathcalls withpathlib.Path.” - Porting: “Convert this function to JavaScript, keeping the same argument names.” Useful when you’re moving a helper from a Python Repl into a Node one.
Always run the transformed code against the same test input as the original. Refactors are where quiet behaviour changes hide, particularly around sorting stability and type coercion.
Building the survey cleaner, start to finish
Here’s how that 20-minute session actually goes. Copy the raw CSV into your Repl’s file tree. In clean_survey.py, write the comment header and import pandas as pd. Type the signature def dedupe_rows(df, key_columns): with a docstring, then let Generate Code fill the body using the spec from Step 3.
Run it against a five-row test file with one deliberate duplicate. When it works, ask in chat for a second function, normalise_columns(df), that lowercases headers and strips whitespace. Chain them in a main() guarded by if __name__ == "__main__":. Then ask for a third pass that writes the result to cleaned.csv and prints a row count before and after.
The whole script lands around forty lines. More importantly, you can read every one of them, because you specified each piece rather than accepting whatever appeared.
Where Ghostwriter gets it wrong
Three failure modes show up repeatedly. It invents library methods that look plausible but don’t exist, especially in less common packages. It reaches for a pandas pattern that was idiomatic three versions ago, so check anything involving applymap or chained assignment. And it forgets context in longer files, which is why keeping generated functions small and self-contained beats one giant generated block.
The fix in each case is the same: run the code on real input immediately. Ghostwriter is confident at exactly the same volume whether it’s right or wrong, so execution is your only reliable filter.
Habits that make it worth keeping
Write the docstring before the body. Name your functions as if the name were part of the prompt, because it is. Keep a test file open in a nearby tab so you can paste input and output back into chat when something breaks. And treat every generated line as a draft from a fast, slightly overconfident colleague you’re still reviewing.
Do those four things and Ghostwriter stops being a novelty that finishes your brackets. It becomes the part of your editor that handles the scaffolding, the explanations, and the first draft of the boring function, leaving you to decide what the code should actually do.

