Ai Shepherd

LLMMD Memory Web Injection Pattern

Disclaimer 1: I aim to write short blog posts, this isn't one of them.
Disclaimer 2: This is security related, the below story only works if you and only you have full control.

Problem

While living in this IT Ai revolution era, you are hopping agents quite a lot. Although some standards are arising, like AGENTS.md (which might not even be a good thing, considering models react differently) or SKILLS. Locally on my machine all these different memory instruction files are becoming a mess. The main level of mess, I'm talking about is the user global level:

  • ~/.claude
  • ~/.config/opencode
  • ~/.pi
  • etc.

It's these memory files I inject the most into the LLM session.

Memory files need to be installed (put in the right place for the specific agent). Claude Code (CC) has become so popular that other agents actually also look in the specific CC locations.
You can also symlink of course. Good luck.

This memory file pollution situation, was giving me cognitive stress. There needs to be a more elegant way of handling these memory files.

Note: Project specific memory files should simply live in the project repo. These are out of scope. For now.

Signals

There have been 3 important signals I've observed while working with agents.

1. Plain text index files

A while ago I observed CC using a specific documentation task to lookup its own documentation online.

The task will start the lookup at these web resources:

  • https://code.claude.com/docs/llms.txt
  • https://code.claude.com/docs/en/claude_code_docs_map.md

From those index resources it will find and fetch the appropriate documentation. Which again is a more detailed published markdown file. For instance, the user prompting CC for best practices will get the information from this markdown file:

- [Best Practices for Claude Code](https://code.claude.com/docs/en/best-practices.md): Tips and patterns for getting the most out of Claude Code, from configuring your environment to scaling across parallel sessions.

2. Skills as a construct are nothing really

Everybody is talking about skills. Raving about skills. Skills are nothing. No special construct. LLM's behaviour is guided by input text. That's it. There can be some behavioural aspect related to a specific skill, but it's still the LLM deciding if it should be used.

Because a skill is primarily a bundle of text files, they transfer easily. Yay.

3. Progressive disclosure

Skills are built upon the principle, that an LLM doesn't need the whole text of a skill at session init. Only after the LLM decides it needs to "use" the skill based on a short usage description, it will ask for the complete skill instruction text. It's a context engineering efficiency thing.

Experiment

I don't want a digital mess in my life. So based on these observations I started to experiment.

What would be an easier way of handling transferability of text files? Opt-in, right. Where can I opt-in to? Web resources. Let's go.

I've seen that llms.txt more often. It appears to be some kind of standards proposal. Interesting. Maybe I can hook into this?

So what if, I created a (privately managed) set of web resources, that are linked to each other based on indexes? This works. I've tried it in CC, OpenCode and now my new fav. agent: Pi.

It's so simple, it's funny. Elegant? I like simple a lot.

The best way I can describe it is: memory web injection pattern.

LLMMD

I registered llmmd.nl. A place for llm markdown files.
I started to experiment with structure and linking.

The following structure surfaced:

llmmd.nl/
├── llms.txt                          # (1) Entry point
├── guidance/
│   ├── index.md                      # (2) Guidance domain index 
│   ├── <domain>/                     # EXAMPLES: Go, TDD, Principles
│   │   ├── index.md                  # (3) Domain index to <resource-map>.md
│   │   ├── <resource-map>.md         # Guidance knowledge map
│   │   └── etc
└── skills/
    ├── index.md                      # (2) Skills index
    ├── <skill>.tar.gz                # Compressed skill archive
    └── etc

There is a difference between static and dynamic LLM text.

  • static: represents guidance that the LLM must follow. There is no specific executable behaviour associated. Think reviewing, following style guides etc. It can be progressively loaded into memory.
  • dynamic: these are your skills. Flat file instructions and programmable behaviour. In case of my current Pi setup, these contain Bun ts scripts. This needs to be cached locally.

My current Pi setup does the following:

  • It bootstraps the llms.txt on session init. (and the AGENTS.md, because, why not). Pi created an extension for this. OpenCode provides this out of the box through opencode.json.
  • The moment it needs a guidance or skill, it will traverse (through the index.md's) the tree and make it so.

I asked Pi to take care of the skill caching, and it simply created a skill for this.

Conclusion

For these governing texts, there is now a structure/pattern, that enables different agents to hook into, with minimal effort. It enables you to quickly iterate on those LLM nudges. Because, don't forget the only thing we do now is: programming the magical box.

Bonus

Bootstrapped and all:

llmmd bootstrapped in Pi