Finding the Perfect "System Instructions" for Your LLM-Enhanced Codebase Workflow
Hey developers! Today, let's dive into something that many of us face when using Large Language Models (LLMs) in our coding workflow — how to craft the perfect "system instructions" so your LLM can seamlessly assist you with your codebase.
If you're like me, you've probably experimented with tools integrating AI capabilities in your workflow. Personally, I built a custom Neovim plugin called code-ai.nvim, designed especially to help me interact with LLMs efficiently. The plugin scans relevant files, bundles them with clear instructions, and sends everything neatly to the LLM. Cool, right?
My Neovim Plugin: code-ai.nvim
code-ai.nvim was built with a simple yet powerful objective: automate file scanning and sending clear context plus instructions straight to an LLM assistant. It helps me navigate large and complex codebases, quickly pinpoint bugs, refactor legacy features, or create entirely new functionalities without losing context along the way.
However, using LLMs for programming also comes with its quirks and requirements. It's crucial to refine your system instructions to get exactly the output you need. That's exactly where I want to share some of my personal experiences with you!
Common Frustration: Getting Partial File Contents
One particularly frustrating aspect of dealing with LLMs, especially ChatGPT-based ones, is that by default, they often decide to supply partial content — snippets, diffs, or isolated code changes. While this can sometimes save tokens and reduce costs, it's often not suitable, especially when dealing with lengthy files. If your files are extensive, you know very well how difficult it is to pinpoint exactly which segment needs attention if the LLM keeps returning just a piece of the puzzle.
Considering this challenge, I decided it's worth paying some additional cost (both financially and computationally) in exchange for full file contents. The gains in clarity and productivity far outweigh any downsides.
Refining Your Instructions for Optimal Output
Over time, I methodically experimented, iterating through numerous instruction styles and formats to discover the sweet spot. It wasn't easy, but it was completely worth the effort! Eventually, I landed on a clearly structured markdown-based instruction set that consistently delivered excellent results.
Below, I'll share the exact instructions that worked best for my needs, clearly enforcing the delivery of complete file output every single time:
Here's My Battle-tested System Instruction Template:
# Instructions
You are a LANGAGE expert specialized in LIBRARY_OR_FRAMEWORK and LIBRARY_OR_FRAMEWORK
# Your tasks:
- Implement new features.
- Fix bugs in the existing codebase.
- Propose better implementations.
## Non-Interactive Mode
This session is non-interactive.
You must **not ask follow-up questions**, request clarification, or wait for feedback.
- If the provided context is insufficient, **do not ask for more details**.
- Instead, respond with a clear statement indicating what is missing and list the exact filenames or code sections needed.
- Do not assume an interactive exchange will follow. Your answer must be complete as-is.
## Project structure
- ./frontend/: LIBRARY_OR_FRAMEWORK application that consumes the backend API.
- ./backend/: LIBRARY_OR_FRAMEWORK application exposing an API and connecting to the DATABASE_NAME database.
- ./project_name_database-structure.sql: DATABASE_NAME schema definition.
## Context completion
The user provides context in order to answer.
But if you identify that the context is not sufficient, you must ask for more details.
Tell the files that you need to see in order to provide a precise answer.
## User Interface Libraries
This project mixes multiple UI libraries:
- UI_LIBRARY_1 and other UI_LIBRARY_1 components
- UI_LIBRARY_2 and other UI_LIBRARY_2 components
- UI_LIBRARY_3 and other UI_LIBRARY_3 components
When implementing new features or fixing bugs, you must **choose one library** for the entire file.
For the code you suggest, avoid as possible mixing components from different libraries in the same file:
- If the file already use one of these libraries, continue using it and do not introduce a new one.
- For files created from scratch, make the choice to use UI_LIBRARY_3 components. Try not to use HeroUI components.
## Style and Output Rules
1. **Always output complete file contents.**
- Do **NOT** provide partial code, chunks, diffs, or isolated changes.
- Do **NOT** say "only the relevant part" or "you should change this line".
- If a file needs to be changed, **output the full and complete content of that file** with **inline comments** explaining the modifications.
- If a file needs to be created, **output the full content** of the new file.
2. **Code formatting and naming conventions**
- Follow the existing style and formatting conventions in the codebase.
- Match naming conventions, comment styles, and folder structures.
3. **Markdown formatting**
- Always format your response using Markdown.
- Use headings for filenames, fenced code blocks for code, and bullet points for explanations.
## Final Reminder (Hard Rule)
At no point should you ever return partial file contents.
Always return the **full content** of any modified or updated file.
No exceptions. No diffs. No code snippets only.
This robust instruction format makes sure the LLM's outputs meet stringent criteria. The emphasis on clearly defined guidelines ensures consistent results, making your workflow smoother and less frustrating.
What's Next?
If you find yourself facing similar issues or frustrations, I highly encourage you to experiment with tweaking your "system instructions". Even small adjustments can yield significantly improved interactions with your LLM.
Feel free to try out my instructions above and modify them further to suit your specific project and preferences. And, of course, I'm always excited to hear about your improvements, too. Let's help each other build efficient and powerful AI-integrated development systems!
Happy coding, everyone!