Go to content|Go to the main menu|Go to search

edhouse-CookieGdpr-Policy-s
1073657
2
/en/gdpr/
107650B6A

Back to Blog

Tutorials

How to build a shared universal AI harness?

8.9.2026Ondřej Květ

Every project that uses LLMs for generating code, tests, or documentation should include some kind of harness – a set of rules that defines how the agent should behave. Unfortunately, the configuration of these rules is still inconsistent; the individual cloud AI tools (Copilot, Codex, Claude) each use different formats. Our team is made up of people from different organizations, so we set out to create a harness that would be common to all tools and lead to similar agent behavior.

Universal?

First of all, we need to think about what kind of universality we actually want to achieve. Supporting all tools is currently unrealistic, because we would end up with a limited intersection of compatibility and our options would keep shrinking. On our project, Copilot has historically been the most widely used tool, and over time we added Codex CLI and Claude CLI. This article mostly focuses on these three tools.

What do we want to achieve?

First and foremost, we definitely don't want to duplicate our instructions in any way. The harness should be simple, yet it will change frequently – the DRY principle is essential. For security reasons, I wanted to avoid dynamically downloading instructions from the Internet, mostly due to concerns about supply chain attacks. Another reason is that such solutions are often quite complicated, and their added value is questionable.

Our team maintains about 10 git repositories that together make up one large project. We therefore wanted to create a harness that would be easily shared across all of them.

The base instruction file

The base instruction file is the single file that gets loaded at the start of every agent session (often more than once). This file should be specific to each repository. It's the place where we define how the agent should behave in the context of a given repository. Because it's always loaded, it should be concise and generic; that is, relevant to every prompt we might use within the repository's context.

AGENTS.md has over time become a standard that most tools respect. Among our trio (Copilot, Codex, Claude), only Claude doesn't respect it (unfortunately it still insists on its own CLAUDE.md). One solution is to create CLAUDE.md as a symlink to AGENTS.md. The downside, however, is that symlinks can't be shared via git (without additional client-side configuration on Windows).

A better solution is to use Claude's special @file-import syntax. If the agent encounters a relative file path following an @ character, it loads the entire file and inserts it into its context. So we create an AGENTS.md file that contains all our instructions, and in the CLAUDE.md file we write only @AGENTS.md.

The compatibility intersection

Below is a brief overview of what each tool supports and how they differ:

1) Skills

Skills let you extend an agent's capabilities with new specialized knowledge and procedures. Based on a short description, the agent decides on its own when to load and use a given skill. The skill definition is standardized and widely supported. However, each tool looks for skills in a different location at the repository level: Claude in .claude/skills/; Copilot and Codex support the standard location .agents/skills.

2) Subagents

Subagents are separately defined roles in the development process (tester, reviewer, developer, ...). Each has its own system prompt, a set of allowed tools, and optionally its own model to use. Claude, Copilot, and Codex all support subagents, but each uses a completely different way of configuring them.

3) Prompts and slash commands

Prompts are stored text templates with instructions for agents, which the user can invoke instead of typing them out repeatedly. Slash commands are a way to invoke a stored prompt in a chat with the agent (e.g. /review). Both of these features are gradually being replaced by skills, since skills allow both automatic and explicit invocation as needed.

4) Instructions

Instructions are rules tied to a specific part of a repository (typically via paths or applyTo), so they're only added to the agent's context when it's working on the corresponding files. Both Claude (.claude/rules/*.md) and Copilot (.github/instructions/*.instructions.md) support instructions, but each has its own definition format. Codex doesn't support this yet and addresses a similar need indirectly, through a hierarchy of nested AGENTS.md files.

5) MCP

MCP (Model Context Protocol) is an open standard that lets an agent connect to external tools and data sources (databases, APIs, file systems) through a unified interface. All three tools support the protocol itself; what differs is the configuration method. Claude in .mcp.json, VS Code (Copilot) in .vscode/mcp.json, Copilot CLI in .mcp.json, Codex in config.toml.

Standardization of tool settings is improving over time, but many obstacles remain. One option is to write a script that would generate configurations for all the required tools from a single standard format, directly in the developer's environment. Because of the high complexity and a certain amount of fragility of this approach, we rejected this option and looked for other solutions.

Plugins as a solution?

Agent plugins are a mechanism that lets you share settings without having to copy or duplicate individual files. Fairly recently (August 6, 2026), a new open standard for organizing agent plugins was released. So far, this standard only supports skill and MCP server definitions.

Unfortunately, the same situation as with AGENTS.md repeats itself here, because Anthropic doesn't support this standard and insists on its own Claude plugin definition. This leaves us with a fairly complicated matrix, because the Claude plugin format is supported by a large number of tools (via compatibility or legacy layers):

ClientClaude plugin format supportAgent Plugins 1.0 support
Claude CLI
Copilot CLI
Copilot VSCode
ChatGPT✅*
Codex CLI✅*

(*) Installing the plugin at the repository level doesn't support the Claude configuration. It must be configured in .agents/plugins/marketplace.json.

So if we want to use this mechanism while also supporting all three tools (Claude, Codex, Copilot), we have to settle for just skills and MCP servers, and we need to define the plugin manifest in both formats.

A major downside of the Agent Plugins standard is that it only defines the format of the plugin manifest itself. It doesn't address at all how the plugin should be installed and distributed. For our harness, this is a fundamental problem, because we want the plugin to install automatically the first time each tool we use is opened on the repository.

Creating the harness repository

Since we want to share the harness across multiple repositories, it makes sense to separate it from the rest of the project and create a standalone repository for it. I created a sample repository as a minimal example that defines a shared harness supporting both the Claude and Agent Plugins 1.0 standards. The repository contains an example skill and an example MCP server to demonstrate functionality. The repository structure is as follows (the sample shared harness repository is available on GitHub):

shared-ai-harness-example/

├── .claude-plugin/
│   ├── marketplace.json    // Claude plugin marketplace manifest
│   └── plugin.json         // Claude plugin manifest

├── skills/
│   └── example-skill/
│       └── SKILL.md        // Example skill

├── mcp-server/
│   └── server.py           // Example MCP server

├── claude.mcp.json         // MCP configuration for Claude
├── mcp.json                // MCP configuration for the Agent Plugins standard
└── plugin.json             // Agent Plugins standard manifest

Notice that the skill and MCP server definitions are shared between both formats. Only the surrounding boilerplate differs: the plugin manifests and their location. The manifests for both plugins are very similar. I deliberately chose different names so it would be possible to tell which one gets loaded.

The plugin manifest under the Agent Plugins standard is defined in the plugin.json file:

{
    "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
    "name": "example-plugin",
    "version": "1.0.4",
    "description": "Example plugin for the agent-plugins.org standard.",
    "author": {
        "name": "Ondra Květ"
    },
    "license": "MIT",
    "repository": "https://github.com/ondrej-kvet/shared-ai-harness-example"
}

The Claude manifest is defined in the .claude-plugin/plugin.json file:

{
    "name": "claude-plugin-example",
    "version": "1.0.4",
    "description": "Example plugin for Claude.",
    "author": {
        "name": "Ondra Květ"
    },
    "mcpServers": "./claude.mcp.json"
}

The Claude plugin definition must also include a marketplace manifest: a file that defines which plugins the repository contains and where they should be read from:

{
    "name": "shared-ai-harness-example",
    "description": "Example marketplace plugin for Claude.",
    "owner": {
        "name": "Ondra Květ"
    },
    "plugins": [
        {
            "name": "claude-plugin-example",
            "source": "./",
            "description": "Example plugin for Claude."
        }
    ]
}

This file is also the biggest difference between the two formats, since the Agent Plugins standard has no concept of a marketplace at all.

Using the harness repository

In general, plugins can be installed at three different levels (though not every tool supports all three levels):

  • Repository: the plugin is available to everyone who opens the repository (suitable for a shared harness).
  • User: the plugin is available across every repository the user opens (suitable for personalization).
  • Organization: the plugin is available across every repository within the organization.

In our example, we'll demonstrate using the harness at the repository level. So I created one more repository that consumes our harness (also available on GitHub).

As already mentioned above, each tool has its own way of installing and behaves differently:

1) Claude CLI

Claude lets you automatically enable a plugin; however, this setting only offers the user the option to install the plugin after launch (automatic installation doesn't actually happen).

The plugin is configured in the .claude/settings.json file:

{
        "enabledPlugins": {
            "claude-plugin-example@shared-ai-harness-example": true
        },
        "extraKnownMarketplaces": {
            "shared-ai-harness-example": {
                "source": {
                    "source": "github",
                    "repo": "ondrej-kvet/shared-ai-harness-example"
                },
                "autoUpdate": true
            }
        }
    }

2) VS Code (Copilot)

In VS Code, agent plugins are managed in the shared Extensions view. Automatic plugin installation isn't supported; it needs to be installed manually via the @agentPlugins @recommended filter. The implementation feels unpolished, since, for example, it's not even possible to check the installed plugin's version.

VS Code supports the same configuration as Claude's .claude/settings.json. It also supports its own location at .github/copilot/settings.json (where it expects the same format as the Claude configuration).

3) Copilot CLI

Copilot CLI also supports the same configuration as Claude. Here, the plugin is automatically installed on launch, including a working MCP server.

4) Codex CLI and the ChatGPT app

Codex CLI shows the plugin as available under Repository Codex Plugins (via the /plugins command), but again it must be installed manually. The INSTALLED_BY_DEFAULT parameter doesn't work in the current version. The ChatGPT app behaves similarly.

The plugin is configured in the .agents/plugins/marketplace.json file:

{
        "name": "repo-marketplace",
        "interface": {
            "displayName": "Repository Codex Plugins"
        },
        "plugins": [
            {
                "name": "example-plugin",
                "source": {
                    "source": "url",
                    "url": "https://github.com/ondrej-kvet/shared-ai-harness-example.git",
                    "ref": "main"
                },
                "policy": {
                    "installation": "INSTALLED_BY_DEFAULT",
                    "authentication": "ON_INSTALL"
                },
                "category": "Productivity"
            }
        ]
    }

In the current version, neither OpenAI app supports installing plugins at the repository level. Once installed, the plugin always ends up in the personal context. Let's hope this changes in the future.

In conclusion

The road to standardizing AI tool configuration is still an uphill battle. We've had a few wins (AGENTS.md, skills), a few losses (Anthropic and its reluctance to support standards), and a few compromises (plugin distribution). To build the most universal yet still simple harness, I recommend the approach outlined in the examples: AGENTS.md with CLAUDE.md as a fallback, the Claude plugin for Anthropic and legacy support, and the Agent Plugins standard for future development. At the same time, I'd recommend keeping an eye on developments around agent standardization, since the current situation is evolving very quickly.

In my view, standardization is very important. The history of the IT industry shows the dangers of vendor lock-in and the path it leads to: stagnation (Internet Explorer serves as a cautionary example).

Share article

Author

Ondřej Květ

Ondřej KvětA software developer and technical lead with a strong interest in software architecture and system design. In addition, I teach computer science part-time at a secondary school.

Edhouse newsletter

Get the latest updates from the world of Edhouse – news, events, and current software and hardware trends.

By signing up, you agree to our Privacy Policy.

Thank you for your interest in subscribing to our newsletter! To complete your registration you need to confirm your subscription. We have just sent you a confirmation link to the email address you provided. Please click on this link to complete your registration. If you do not find the email, please check your spam or "Promotions" folder.