Every developer who uses AI coding assistants long enough develops the same tic.

You start every prompt with a little speech.

“Be concise. Include examples. Explain intent, not just code. Don’t refactor things I didn’t ask you to touch. Don’t add dependencies without asking. Don’t—”

You’re not prompting anymore. You’re parenting.

And the worst part? It works — until the one time you forget a sentence. Then the assistant reads that omission as creative license and rearranges your living room while you asked it to change a lightbulb.

This is the prompt tax. You pay it every single time. And it scales terribly.


The prompt tax (and why it compounds)

Most AI interactions are stateless in practice. Sure, there’s a context window, but instructions from three prompts ago are already being diluted by new information. The model doesn’t remember that you prefer explicit error handling, or that you hate magic strings, or that “refactor” means “move this function, not rewrite the module.”

So you repeat yourself. And the repetition creates three problems:

  1. Fatigue. You get tired of typing the same preamble. You start abbreviating. The output quality drops. You blame the model.

  2. Drift. Tuesday-you writes a thorough instruction set. Friday-you writes “just fix it.” The results diverge. The codebase diverges.

  3. Tribal knowledge. Your carefully crafted prompt lives in your head (or your clipboard history, which is basically the same thing). Your teammate doesn’t have it. Neither does your future self after a long weekend.

The prompt tax isn’t just annoying. It’s a consistency problem wearing an inconvenience costume.


What if you could save your instructions?

Not as a text file you copy-paste from. Not as a system prompt you configure once and forget. Something in between.

Picture this: a small collection of Markdown files in your repo, each one defining a behavior mode for your AI assistant.

  • documentation.md — “When writing docs, explain intent first. Include examples. Don’t just describe function signatures.”
  • security.md — “Think like an attacker. Focus on practical mitigations, not theoretical CVE lists.”
  • testing.md — “Write behavior-driven tests. Test boundaries and edge cases. Don’t mock everything into oblivion.”
  • refactoring.md — “Reduce coupling. Respect existing boundaries. Don’t rename things for fun.”

Then, when you need one, you invoke it:

Using security skill, review the authentication flow for injection risks

The tool reads the Markdown file and injects it into the system prompt - the part the model treats as instructions from the operator, not casual conversation.

Your prompt stays short. The behavior stays consistent. And the instructions live in the repo, not in your head.

I call these skills. But you could call them presets, personas, modes, lenses - whatever. The name matters less than the pattern.


Why Markdown files in a directory?

I know what you’re thinking. “This is just a prompt template library.” And you’re not wrong. But the where and how matter more than you’d expect.

They live in the repo

This means they’re version-controlled. They go through code review. When someone on your team writes a documentation.md skill that says “always include usage examples,” that decision is visible, reviewable, and shared.

You’re not just saving prompts. You’re version-controlling your team’s taste.

Code style guides exist because “write clean code” isn’t specific enough. Skills exist because “be a good assistant” or “you are a super-expert senior software engineer” isn’t specific enough.

They’re scoped per project

Your open-source library needs different AI behavior than your internal microservice. The library wants careful public API documentation, backwards compatibility awareness, and changelog entries. The microservice wants fast iteration, infra-aware suggestions, and monitoring hooks.

Same developer, different context. Repo-local skills handle this automatically.

They’re composable

Need docs and security awareness for a single task?

skills:security,documentation review and document the auth module

Two Markdown files get injected. The model gets both sets of instructions. You typed one line.

They’re transparent

No hidden configuration. No settings buried in a YAML file three directories up. If you want to know what skill:testing does, you open skills/testing.md and read it. If you disagree, you edit it and commit.

The system is legible. That matters more than most people think.


What makes a good skill?

Not everything belongs in a skill file. The best ones share a few properties:

They describe a mindset, not a checklist.

Bad: “Always add type hints. Always add docstrings. Always use f-strings.”

Good: “You’re writing code that a junior developer will maintain alone. Prioritize clarity over cleverness. Prefer explicit patterns over implicit conventions.”

The first is a linter. The second changes how the model thinks.

They’re focused.

One skill per concern. Don’t make a be_good_at_everything.md kitchen sink file. A security skill shouldn’t also contain formatting preferences, and a documentation skill shouldn’t also contain performance tips.

Keep them small. Compose them when you need more than one.

They express opinions.

The whole point is consistency. “Consider testing” is useless. “Write tests that describe behavior, not implementation. Prefer integration tests for I/O boundaries. Mock only what you must” - that’s a skill with a point of view.

Your skills should sound like the best version of your team’s code review comments. Specific, opinionated, and useful.

They assume the model is capable but amnesiac.

You’re not teaching the model how to code. You’re reminding it what you care about. The difference between a good AI response and a great one usually isn’t capability - it’s context about your preferences.

Skills provide that context. Repeatedly. Reliably. Without you typing it again.


The consistency argument (or: why drift will ruin you slowly)

Here’s the thing about prompt drift that nobody warns you about: it’s invisible.

You don’t notice it happening. One day you write a thorough prompt and get beautiful, well-structured code. The next day you’re tired and write something shorter. The output is slightly different. Not worse, exactly - just different. Different naming. Different patterns. Different assumptions.

Multiply that across a team of four over two months and your codebase starts to look like it was written by eight people with conflicting philosophies. Because it was.

Skills don’t eliminate drift. But they create a gravity well - a default behavior that holds unless you actively override it. The model still has its moods (they all do), but instead of freestyling from a blank slate every time, it’s freestyling within guardrails that your team defined.

That’s a massive difference.


The tools-that-write-files problem

This pattern becomes especially important with tools that let AI write directly to your filesystem - what some call an “optimistic” or “agentic” workflow.

When the AI just suggests code in a chat window, inconsistency is annoying but harmless. You copy-paste what you like, edit the rest, move on.

But when the AI writes directly to disk? Inconsistency lands. It becomes committed code, merged PRs, production behavior. The gap between “the model was in a weird mood” and “we shipped a bug” shrinks to nothing.

In that world, skills aren’t a convenience. They’re a safety mechanism. They’re the difference between “the AI followed our conventions” and “the AI decided this module should use a completely different error handling pattern than everything else.”

The more authority you give the model, the more important it is to tell it how to behave - and to tell it the same way every time.


Design principles that matter

If you’re building this pattern into a tool (or adopting it for your own workflow), a few design decisions are worth getting right:

Explicit invocation beats auto-detection.

It’s tempting to have the tool guess which skill to apply based on the prompt content. Resist this. Auto-applied behavior that the user didn’t ask for is spooky. It makes debugging harder and trust lower.

Let the user say skill:security. Don’t try to infer it from the word “vulnerability” appearing in their prompt.

System-level injection beats user-level injection.

Skills should be injected as system prompt content, not as a user message the model might deprioritize. System-level instructions get treated as operator guidance. User-level instructions compete with everything else in the conversation.

This distinction matters more than it sounds. It’s the difference between a suggestion and a directive.

Ambiguity should resolve to “do nothing.”

If the tool can’t figure out which skill the user meant - apply none. Don’t guess. The user can rephrase. Silently applying the wrong behavior preset is worse than applying no preset at all.

Keep them readable. Keep them auditable.

Skills should be injected with clear delimiters so that logs and debug output make it obvious what instructions were active. “Why did the model do that weird thing?” should always have an answerable investigation path.


How we built it in Aye Chat

We shipped skills as a first-class feature in Aye Chat. Here’s the short version:

  • Skills live in a skills/ directory at the repo root (auto-discovered by walking upward from the working directory, monorepo-friendly).
  • Only *.md files, flat directory, no recursion. Boring on purpose.
  • You invoke them with skill:name or skills:name1,name2 or using name skill in your prompt.
  • They’re injected into the system prompt with clear delimiters.
  • Fuzzy matching exists but is intentionally conservative: high threshold, at most one match, and if two skills tie, neither is applied.
  • Results are cached in memory, invalidated by directory mtime. One cheap stat() call per request.

You can see our own skill files on GitHub - documentation.md, security.md, testing.md, modularization.md, performance.md, and repo-exploration.md. Feel free to steal them as starting points for your own.

The implementation is small (~200 lines of Python), but the leverage is disproportionate. Once your team has a shared skills/ directory, every prompt becomes shorter and every output becomes more predictable.


The real takeaway: codify your taste

Every team has implicit preferences. How errors should be handled. How tests should be structured. How documentation should read. What “clean code” means in this repo, not in a textbook.

Those preferences usually live in people’s heads, sometimes on a wiki page nobody reads, occasionally in a linter config that covers 10% of what you actually care about.

Skills are a way to make those preferences explicit, portable, and reusable - in a format that both humans and AI assistants can read.

You’re not writing prompt templates. You’re codifying your team’s engineering taste into something version-controlled and composable.

And the next time you’re about to type “please be concise, include examples, explain intent, don’t refactor things I didn’t ask-” you can just write skill:documentation and get on with your day.

Your future self will thank you. Probably with a short, well-documented message.


About Aye Chat

Aye Chat is an open-source, AI-powered terminal workspace that brings AI directly into command-line workflows. Edit files, run commands, and chat with your codebase without leaving the terminal - with an optimistic workflow backed by instant local snapshots.

Support Us

  • Star our GitHub repository - it helps new users discover Aye Chat.
  • Spread the word. Share Aye Chat with your team and friends who live in the terminal.