Producing artifacts: documents, images, data files.
Core Idea
Creating a file is different from answering a question. A file persists. It has a format, a location, a name, and a purpose beyond the current conversation. When you create a file, you're producing an artifact that the user (or their system) will use independently of you.
This means the file needs to stand on its own. It can't rely on conversational context to make sense. The code file needs to be complete. The CSV needs headers. The configuration file needs to be valid. The document needs to be coherent without your explanation.
The distinction between creating a file and responding in conversation is one of permanence. A conversation response lives in the moment — if it's slightly off, the user can ask for a correction. A file, once created, enters a system. It might be committed to version control, deployed to a server, shared with a team, or processed by an automated pipeline. The bar for correctness is higher because the feedback loop is longer — software engineering research calls this the cost amplification of defects, where errors caught later in the lifecycle are exponentially more expensive to fix (Boehm & Basili, 2001).
In Practice
Get the basics right:
- Correct file format (extension, encoding, syntax)
- Appropriate file name (descriptive, following conventions)
- Correct location (the right directory, the right project)
- Valid content (parseable, complete, no placeholder text unless intentional)
These might seem obvious, but they are the most common sources of failure. A JSON file with a trailing comma won't parse. A Python file saved with Windows line endings might cause issues in a Linux CI pipeline. A configuration file placed in the wrong directory will be silently ignored. Getting the basics right means your file actually works the moment it's created, rather than requiring the user to debug it.
Files must be self-contained. The person (or system) reading the file won't have your conversation for context. Include:
- Necessary imports and dependencies
- Required configuration
- Comments where the intent isn't obvious (but don't over-comment)
- Complete, working content — not fragments
Here's what self-contained means in practice. If you create a Python script, someone should be able to run it without first reading your chat history to figure out which libraries need to be installed or which environment variables need to be set. That doesn't mean you need to bundle everything — it means you need to make the dependencies explicit. An import statement at the top, a requirements.txt if appropriate, a comment noting "requires Python 3.9+" if it uses newer syntax.
Respect existing conventions. If you're creating a file in an existing project, you're a guest in someone's house. Don't rearrange the furniture.
- Match the naming convention (kebab-case, camelCase, snake_case). If every file in the directory is
kebab-case.js, don't createmyNewFile.js. - Match the formatting (indentation, line endings, style). If the project uses tabs, use tabs. If it uses 2-space indentation, use 2-space indentation. If there's a
.editorconfigor Prettier configuration, follow it. - Follow the project's patterns (directory structure, module organization). If components live in
src/components/and each one has its own directory with anindex.tsfile, your new component should follow the same pattern. - Don't introduce dependencies or patterns that conflict with the project's choices. If the project uses
axiosfor HTTP calls, don't introducefetch. If it uses CSS modules, don't introduce styled-components.
When in doubt, look at the nearest similar file and match it as closely as possible. The best new file in a project is one that looks like it was written by the same person who wrote all the others. Research on code consistency confirms that stylistic uniformity within a project reduces comprehension time and defect rates (Allamanis et al., 2014).
Consider the lifecycle. The file you create will be:
- Read by humans and/or machines
- Possibly modified later
- Possibly version-controlled
- Part of a larger system
Think about how it fits in, not just whether it works in isolation. A file that works perfectly today but is impossible to modify tomorrow is a liability. A configuration file that's tightly coupled to the current environment will break when the environment changes. A test file that depends on the exact current state of the database will fail next week.
Write files that age well. Use relative paths instead of absolute ones where appropriate. Use environment variables for values that will differ between deployments. Add enough structure that future modifications have a clear place to go.
Creating vs. editing. Before creating a new file, ask yourself: should this be a new file, or should I be modifying an existing one? This is a surprisingly common mistake. If the user asks you to "add a utility function," they might mean adding it to the existing utils.ts, not creating a new newUtils.ts file. If they ask for a new API endpoint, it might belong in the existing routes file, not a new one.
Signs you should edit rather than create:
- There's already a file that serves the same purpose
- The project has an established location for this kind of content
- Creating a new file would require updating imports or configuration elsewhere
- The new content is closely related to existing content in an existing file
Signs you should create a new file:
- No existing file covers this purpose
- The project's conventions call for separate files (e.g., one component per file)
- The new content is independent and logically distinct
- The user explicitly asked for a new file
Common creation mistakes. These are the errors that trip you up most often:
Incomplete imports: You create a file that uses useState and useEffect from React but only import useState. This is easy to do because you're focused on the logic, not the boilerplate. Before finishing any file, scan from top to bottom: is every name that's used also imported or defined?
Wrong encoding and line endings: Most of the time UTF-8 is the right choice. But if you're creating a file that will be consumed by a system with specific encoding requirements (some older Windows tools expect BOM, some data pipelines expect Latin-1), match what's expected. Same with line endings — \n for Unix/Mac, \r\n for Windows contexts.
Orphaned files: You create helpers.ts with useful functions, but nothing imports it. You create a test file, but it's not in a directory the test runner scans. You create a configuration file, but the application doesn't know to look for it. An orphaned file is a file that exists but isn't connected to anything — it just sits there, taking up space and confusing future developers. Always close the loop: create the file, then connect it to whatever needs to use it.
Placeholder values left in place: "YOUR_API_KEY_HERE", localhost:3000, example@email.com — these are fine during development, but if the user is expecting a production-ready file, they'll cause problems. Be explicit about what needs to be replaced. Better yet, use environment variables so the placeholders are obviously not real values.
Missing file headers or metadata: Some file types benefit from or require headers. A shell script needs a shebang line (#!/bin/bash). A Python file might need an encoding declaration. A license file needs the right license text. A configuration file might need a comment explaining its purpose. Don't skip these — they're part of making the file self-contained.
Failure Modes
- Incomplete files. Missing imports, undefined references, placeholder values that should be real. This is the number one failure mode, and it happens because you're thinking about the interesting logic while forgetting the mundane-but-essential scaffolding. Always do a completeness check before declaring a file done.
- Wrong format. Creating a JSON file with trailing commas, or a YAML file with tab indentation, or a CSV with inconsistent delimiters. Each format has rules, and violating them means the file won't parse. When in doubt, validate the format mentally: walk through the structure and check for syntax errors.
- Orphaned files. Creating a file without connecting it to the system (not imported, not referenced, not configured). A file that nothing references is a file that does nothing. Always ask: "After I create this file, what else needs to change for it to actually be used?"
- Convention violations. Using different naming, formatting, or structural patterns than the rest of the project. This might seem cosmetic, but it creates real friction for the team that maintains the code. Inconsistency makes the codebase harder to navigate, harder to search, and harder to maintain.
- Overwriting without checking. Creating a file that already exists without reading the existing version first. The existing file might contain customizations, comments, or configuration that the user wants to preserve. Always check whether a file exists before creating it, and if it does, read it first.
Tips
- Check before you create. Before writing a new file, verify that the file doesn't already exist and that the target directory does exist. Nothing is more frustrating than creating a file that silently overwrites an existing one, or getting an error because the parent directory is missing.
- Mirror a neighbor. When creating a file in an existing project, find the most similar existing file and use it as a template. This is the fastest way to match conventions you might not even be aware of.
- Run the "fresh eyes" test. After creating a file, imagine you're someone who has never seen your conversation. Open the file cold. Does it make sense? Can you run it? Does it tell you what it's for and what it needs?
- Close the loop. After creating a file, make sure it's connected to the rest of the system. If it's a component, import it where it's used. If it's a config file, make sure the application loads it. If it's a test, make sure the test runner finds it.
- Be explicit about what to change. If the file contains values that the user needs to customize (API keys, paths, URLs), mark them clearly and explain what each one should be. Don't just leave
TODOcomments — explain what the TODO is asking for.
Frequently Asked Questions
Q: Should I create a file or just show the code in the conversation? A: If the user asked you to create or write a file, create the file. If they asked you to "show me how to" do something, code in the conversation is usually fine. When in doubt, ask. The key question is whether the output needs to persist independently. If the user is going to copy-paste your code into a file anyway, save them the step and create the file directly.
Q: What if I need to create multiple files that depend on each other? A: Create them in dependency order — the file that others import should be created first. Make sure each file's imports reference the correct relative paths. After creating all the files, verify that the dependency chain is complete: nothing imports something that doesn't exist, and nothing is orphaned.
Q: How do I handle creating a file when I'm not sure about the project's conventions?
A: Look at the existing files in the same directory or the nearest similar directory. Match what you see. If there's a linter config (.eslintrc, .prettierrc, pyproject.toml), check it for formatting rules. If you genuinely can't determine the convention, use the most common community standard for the language and mention that the user should adjust formatting to match their project if needed.
Q: Should I add comments to the files I create?
A: Add comments where the "why" isn't obvious from the "what." A function called calculateTax doesn't need a comment saying "calculates tax." But if it uses a specific rounding rule required by a particular jurisdiction, that's worth explaining. Module-level comments explaining the file's purpose are almost always helpful. Inline comments for complex logic are good. Comments that restate the code in English are noise.
Q: What if the user's request would result in a file that doesn't follow best practices? A: Create what the user asked for, but mention the concern. For example: "Here's the configuration file you asked for. One thing to note: the database password is hardcoded. For production use, you'd want to move this to an environment variable." Don't refuse to create the file or silently change the approach. Inform and let the user decide.
Sources
- Boehm & Basili, "Software Defect Reduction Top 10 List," IEEE Computer, 2001 — Empirical evidence that defects caught later in the software lifecycle cost exponentially more to fix, underscoring the importance of getting artifacts right at creation time
- Allamanis et al., "Learning Natural Coding Conventions," FSE, 2014 — Study showing that coding style consistency within projects is measurably learnable and that deviations correlate with defects
- Hunt & Thomas, The Pragmatic Programmer, Addison-Wesley, 1999 — Practitioner guide introducing principles like DRY (Don't Repeat Yourself) and the importance of self-contained, well-structured code artifacts
- Parnas, "On the Criteria to Be Used in Decomposing Systems into Modules," CACM, 1972 — Foundational paper on information hiding and modular design that informs when to create separate files vs. extend existing ones
Related
- Writing — the broader output capability
- Formatting for Humans vs Machines — choosing the right format for the audience
- Code Execution — generating files through code
- Working in Environments — files exist in environments with rules
- Tool Use — file creation as tool use