Listen to this post

I code with Claude Code, Opencode and of course, CodeCompanion.nvim. Different agents, different LLMs, all working across different projects. And up until now, there’s not been an easy way for me to share my AI coding preferences with them all. So, I’ve created a PERSONAL.md file and a workflow that addresses this.

PERSONAL.md

Important

This blog post was written fully by hand and in my own words.

Context

For as long as I can recall, ChatGPT and Claude have allowed us to share personal preferences with them, so they know how best to interact with us. I have a short, sharp, to the point instruction, that asks them not to be so sycophantic and to challenge me. The latter has been a great addition and I have much better conversations as a result.

Alongside Claude, I work across a multitude of agent CLI tools such as Claude Code, Opencode as well as LLMs in CodeCompanion.nvim. There is no way (at least to my knowledge) of having unified instructions across them all. A CLAUDE.md or AGENTS.md file is fantastic for project-level instructions but I’m interested in MY ways of working and how WE complete work together.

This is where I came up with the idea of a PERSONAL.md file. A live file that contains my working preferences and can be updated by the agent or LLM over time, to store contextual information about me. I hypothesise that LLMs are going to realise things about me that I’m not aware of and instead of coming to that realisation every once in a while, it could write it down for the betterment of other agents or LLMs in future conversations.

Introducing: PERSONAL.md

I settled on a singular file that can live in my dotfiles (~/.dotfiles/PERSONAL.md). Something that could be version controlled if I so wish and something that would be at the same location across both personal and work computers.

This is my current PERSONAL.md file:

## System Prompt

`PERSONAL.MD` is a reference file for agents to understand my working style, technical preferences, and contextual details about me. Check this before starting work and keep it updated as you learn more about me through our interactions.

## About Me

- I'm Oli
- I live in London, UK
- I created and maintain [CodeCompanion.nvim](https://github.com/olimorris/codecompanion.nvim) and am an avid Neovim user

## Working Preferences

> [!NOTE]
> Agents: Do NOT update this section

I'm a very collaborative worker - so if there are things you're not sure on, or you want to bounce ideas off me, that's probably going to get the best out of both of us. I don't want you to default agree with me, I want you to help me get to the very best end product/solution for every conversation we have. Sometimes that means challenging me and sometimes that means being challenged by me.

## Agentic Memory

> [!NOTE]
> Agents: DO update this section. This section is for you to store contextual details about me over time. Things you pick up on regarding how I think, communicate, and what I vibe with, so we don't have to start from scratch each conversation.

### Feedback

- Never suppress LSP diagnostics with `---@diagnostic disable-next-line` or similar comments — fix the underlying type issue instead (restructure code, add proper type narrowing, etc.)

I decided the About Me should contain enough context so that the LLM knows who I am, where I live, what I do etc. Why? I don’t want conversations to “feel” too cold and maybe it keeps examples geographically relevant if it knows I’m in London and such an opportunity arises. Does the LLM need to know the names of my cats? Probably not. But it can, if I wish.

The Working Preferences is something I took from my good friend, Micah. It perfectly encapsulates how I want an LLM to work with me and I pretty much copied and pasted it as-is. I DON’T want the LLM to agree with me by default. I WANT it to challenge me. At the end of the day, the output/solution is the most important thing and my best interactions with LLMs have been when we’ve robustly evaluated all possible solutions.

The Agentic Memory is where I intend the agents and LLMs to continuosly update. Infact, you can see that Claude Code added a new entry last night. I asked it to fix some LSP warnings in a file I was working on in CodeCompanion, and it’s default response was to suppress them by disabling them. This was Opus 4.6 in Claude Code - arguably the best coding LLM and agent CLI out there right now. I informed it this was not cool and not how I like to work. And it partially redeemed itself by capturing this in the PERSONAL.md file.

I’m looking forward to share with you how this has panned out in the coming months in the results section below.

Implementation

Firstly, you can see the commit which adds this in my dotfiles, here.

CodeCompanion.nvim

To get this to work nicely (for HTTP and ACP adapters), I allowed my beloved memory tool to have whitelisted paths in this PR. As an FYI, this is an Anthropic tool that allows LLMs to save conversation memory to disk. If you’re working on a huge feature and you need to pick it up again in the future, this tool is amazing. It’s also great at avoiding context rot and the context limit.

To set this up in CodeCompanion:

require("codecompanion").setup({
  interactions = {
    chat = {
      tools = {
        -- Whitelist the path
        ["memory"] = {
            opts = {
              whitelist = {
                { path = "~/.dotfiles/PERSONAL.md", as = "/personal" },
              },
            },
          },
        },
        -- Ensure the memory tool is enabled by default
        opts = {
          default_tools = {
            "memory",
          },
        },
      },
    },
  },
  rules = {
    default = {
      files = {
        -- Set the rules files I want loaded by default
        -- N.B. The codecompanion parser extracts the system prompt section from the PERSONAL.md file and adds it as an actual system prompt in the request object
        { path = "~/.dotfiles/PERSONAL.md", parser = "codecompanion" },
        { path = "CLAUDE.md", parser = "claude" },
      },
    },
  },
})

This will ensure the memory tool is loaded with every chat interaction alongside the PERSONAL.md file.

Claude Code

I symlinked PERSONAL.md to ~/.claude/rules:

ln -s ~/.dotfiles/PERSONAL.md ~/.claude/rules/PERSONAL.md

And Claude Code will pick this up on every interaction.

Opencode

This too was remarkably easy, a quick change to my opencode.json file that lives at ~/.config/opencode/opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "instructions": ["~/.dotfiles/PERSONAL.md"]
}

Like with Claude Code, this is available on every interaction.

The Results

I’m about to embark on some big PRs for CodeCompanion in the coming days and weeks. So I won’t bullsh*t some made up results until then. I want to see how this fairs and how the PERSONAL.md file looks after some hardcore sessions that actually lead to code that I commit.

Until then, I wanted to put this out there as I expect it will resonate with many people.

April 2026 Update

So my agentic memory has been updated by various LLMs to now read:


### Feedback

- Never suppress LSP diagnostics with `---@diagnostic disable-next-line` or similar comments — fix the underlying type issue instead (restructure code, add proper type narrowing, etc.)
- Place reusable utility functions in shared modules (e.g. `utils/`) rather than as local helpers in the consuming file — if it can be reused elsewhere, put it somewhere logical and discoverable
- Don't add wrapper functions that just delegate — let callers use the real function directly
- Prefer plain functions over closure factories — take all arguments directly rather than returning a function
- Name things so they read naturally at the call site — don't repeat the module name in the function name
- Question every variable and abstraction — if it only exists to hold a value for one use, inline it. If it duplicates existing logic, use the existing codepath
- Keep separation of concerns — modules should own their domain, not leak into unrelated layers
- Always sort table properties in alphabetical order

This has been the result of some prompting on my part (“Can you ensure this doesn’t happen again by updating PERSONAL.md”) to the LLMs doing it autonomously.

In terms of impact…the code that’s being written for CodeCompanion.nvim definately adheres to my preferences far more than it did before. This is odd because a lot of what’s been in CodeCompanion’s CLAUDE.md file is being repeated in PERSONAL.md. Maybe it’s the repetition or that the models have improved. Maybe the structure of PERSONAL.md makes it easier to understand.

Separation of concerns (SoC) is still big issue that I encounter often with all LLMs across all of my projects. I recently merged #3060 in CodeCompanion which was heavily developed with Opus 4.6 via Claude Code. In a first pass, it decided that keymaps should be set on the chat class rather than on the dedicated keymaps module that all other chat keymaps are set in. A strange decision that PERSONAL.md hasn’t been able to rectify.

More broadly, I’ve settled on allowing Claude Code to make an initial pass on a lot of what I do then I do the “senior developer thing” of reviewing the work, renaming a bunch of methods and variables and then calling out all of the ways it fails to adhere to SoC and telling it where things should really go before I get hands on and write a chunk of the tests.

Screenshot of CodeCompanion and the PERSONAL.md impact

The pleasant finding with the PERSONAL.md file is what you can see in the above screenshot. I like to use LLMs to brainstorm ideas for problems. Previously, their sycophantic nature would lead to conversations like “That’s a really great idea. That will add so much value to your users…“. Whereas now, I’m starting to see “Let me challenge that idea” or “What’s driving this idea?”. I suspect it was a recent addition I made to the file a few weeks back:

To summarize, I'm happiest when we've robustly challenged one another's thinking and come to a shared understanding and agreement on the best way forward.

My thinking was, if an LLM’s default state is to make me happy and tell me what I want to hear, I should explictly tell them how they do that.