How to Build a Portable AI Agent Stack That Avoids Vendor Lock-In
Use agents.md, skill.md, and standard MCP connections to build an AI agent stack that works across Claude Code, Codex, and Cursor without lock-in.
Why Your AI Agent Stack Is Already Half-Locked In
If you’re building with AI agents seriously, you’ve probably noticed something uncomfortable: every tool wants to be the center of your stack. Claude Code has CLAUDE.md. Cursor has .cursorrules. OpenAI’s Codex CLI has its own configuration format. Each tool does something slightly different, and moving between them means rewriting your setup from scratch.
That’s vendor lock-in — not because anyone is being malicious, but because there’s been no agreed-upon standard for how agents should be defined and what they can do. Until recently.
A portable AI agent stack uses open conventions like agents.md, skill.md, and the Model Context Protocol (MCP) to define agent behavior, capabilities, and tool connections in a way that any compliant runtime can consume. The goal is a setup where your agent logic lives in version-controlled files, not inside a proprietary dashboard, and where swapping runtimes doesn’t mean starting over.
This article walks through how to actually build that stack — what files to write, how to structure them, and how to connect tools in a way that works across Claude Code, Codex, and Cursor without rewriting everything each time.
The Problem With Runtime-Specific Configs
Most AI coding tools and agent runtimes have developed their own configuration conventions:
- Claude Code reads
CLAUDE.mdfor project context and instructions - Cursor uses
.cursorrulesor acursor.directoryfile - OpenAI Codex CLI accepts system prompts through its own config format
- LangChain and CrewAI define agent behavior through Python class definitions or YAML configs
None of these are interoperable. If you build a sophisticated agent configuration for Claude Code and then your team wants to evaluate Cursor, you’re not just switching tools — you’re rebuilding your agent’s behavior from scratch.
The deeper problem is that your agent’s intelligence — its instructions, its understanding of your codebase, its specialized skills — ends up encoded inside whatever runtime you happened to start with.
What portability actually means
A portable agent stack separates three concerns:
- Agent definition — Who is this agent? What are its goals and constraints?
- Skills — What specific capabilities can it invoke?
- Tool connections — How does it connect to external systems?
If those three layers are defined in open, readable files rather than runtime-specific configs, you can point any compliant agent runtime at them and get consistent behavior.
Understanding agents.md
agents.md is an emerging convention for defining agent behavior in a runtime-agnostic markdown file. Think of it as the system prompt for your agent, but stored in your repo rather than hardcoded into a specific tool.
The idea is straightforward: markdown is readable by humans and by LLMs. Any agent runtime that can read a file can consume it. And because it’s plain text, it lives in version control alongside the rest of your code.
A well-structured agents.md file typically contains:
- Agent identity and purpose — A description of what this agent does and who it’s for
- Behavioral constraints — What the agent should and shouldn’t do
- Context about the codebase or domain — Key facts the agent needs to do its job well
- References to available skills — Pointers to the
skill.mdfiles the agent can invoke - Output expectations — How responses should be formatted
A basic agents.md structure
# Agent: Code Review Assistant
## Purpose
Review pull requests for code quality, security issues,
and adherence to our style guide.
## Behavioral Constraints
- Never approve a PR that contains secrets or API keys in plaintext
- Flag, don't fix — suggest changes rather than making them automatically
- Always reference the specific line number when flagging an issue
## Codebase Context
This is a TypeScript monorepo using pnpm workspaces.
The main packages are: `api` (Express), `web` (Next.js 14),
`shared` (common utilities).
## Style Guide Rules
- Use named exports, not default exports
- Prefer `const` over `let` wherever possible
- All async functions must handle errors explicitly
## Available Skills
- See skill.md for: `search_codebase`, `check_security`, `post_comment`
This file lives at the root of your repo (or in a .agent/ directory). Claude Code, Cursor, and other tools can be pointed at it directly.
The key discipline: keep agents.md factual and instructional, not conversational. It’s not a chat message — it’s a specification.
Adapting agents.md for different runtimes
Different tools consume this file slightly differently:
- Claude Code: You can import the contents into
CLAUDE.mdwith a reference, or point Claude at the file explicitly - Cursor: Include the file path in your
.cursorrulesor reference it in the workspace settings - Codex CLI: Pass it as part of your system prompt configuration
Remy is new. The platform isn't.
Remy is the latest expression of years of platform work. Not a hastily wrapped LLM.
The goal isn’t that every runtime reads the exact same file automatically — it’s that you maintain one source of truth and translate from it rather than maintaining multiple separate configs.
Understanding skill.md
Where agents.md defines who an agent is, skill.md defines what it can do. Each skill is a discrete, documented capability the agent can invoke.
The convention works like this: each skill gets its own markdown file (or a named section in a shared skills.md), documenting the skill’s name, purpose, inputs, outputs, and any relevant constraints. The agent runtime can then use these definitions to understand what tools are available and when to call them.
What a skill definition looks like
## Skill: search_codebase
**Description**: Search the codebase for a specific pattern,
function name, or string. Returns file paths and line numbers.
**When to use**: When you need to locate existing implementations,
check for duplicate logic, or find where a function is called.
**Inputs**:
- `query` (string, required): The search term or pattern
- `file_type` (string, optional): Limit results to a file extension
(e.g., `.ts`, `.py`)
- `max_results` (number, optional, default 20): Maximum results to return
**Outputs**:
- Array of `{file: string, line: number, context: string}`
**Constraints**:
- Do not use this skill to search for secrets or credentials
- Limit queries to meaningful patterns — avoid single-character searches
A skill definition is basically an interface contract. It tells the agent what’s available, when to use it, and what to expect back.
Organizing your skills
For simple setups, a single skills.md file with multiple sections works fine. For more complex agent stacks, consider a skills/ directory with individual files:
.agent/
agents.md
skills/
search_codebase.md
post_github_comment.md
check_security_patterns.md
generate_test_cases.md
The advantage of separate files is cleaner version history — you can see exactly when a skill was added or changed, and different team members can own different skills.
MCP: The Tool Connection Layer
The Model Context Protocol (MCP) is an open standard, originally developed by Anthropic, that defines how AI models connect to external tools and data sources. It’s quickly becoming the most important standard in the portable agent stack conversation.
MCP works on a client-server model:
- MCP servers expose tools and data (a database, an API, a filesystem)
- MCP clients are agent runtimes that connect to those servers (Claude Code, Cursor, and others)
The critical point: MCP is runtime-agnostic. An MCP server you build to give Claude Code access to your database works identically with Cursor, with LangChain, or with any other MCP-compatible client. You write the integration once.
Setting up standard MCP connections
MCP connections are typically configured through a JSON file. Claude Code uses claude_desktop_config.json, Cursor has its own MCP configuration panel, and other tools have similar mechanisms.
A basic MCP config looks like this:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "<your-token>"
}
},
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres",
"postgresql://localhost/mydb"]
}
}
}
The Anthropic team maintains a growing registry of official MCP servers for common integrations — GitHub, filesystem access, Postgres, Slack, Google Drive, and more.
Why MCP matters for portability
Before MCP, every agent tool had its own plugin or extension format. Cursor plugins didn’t work in Claude Code. Claude Code integrations didn’t work in Windsurf. Each tool was an island.
MCP changes that. When you configure a tool connection through MCP, you’re not configuring it for a specific AI tool — you’re configuring it for any MCP-compatible client. As more runtimes adopt the standard (and adoption is moving fast), your integration work becomes reusable across your entire agent stack.
Making It Work Across Claude Code, Codex, and Cursor
With agents.md, skill.md, and MCP connections in place, here’s how to actually wire things up across the three most common developer-facing agent runtimes.
Claude Code
Claude Code is the most MCP-native of the three. It reads CLAUDE.md natively, and MCP servers are configured through its settings file.
To use your portable stack with Claude Code:
- Create a
CLAUDE.mdthat imports or references youragents.mdcontent - Configure your MCP connections in
claude_desktop_config.json - Reference available skills in
CLAUDE.mdso Claude knows what tools it has
Claude Code also supports project-level CLAUDE.md files that override user-level configs, which is useful for team setups where different projects need different agent behavior.
OpenAI Codex CLI
Codex CLI is OpenAI’s terminal-based coding agent. It doesn’t natively read an agents.md file, but you can feed your agent definition into it through the system prompt flag or a wrapper script.
codex --system-prompt "$(cat .agent/agents.md)" "Review the changes in this PR"
For MCP, Codex CLI support is more limited at present — check current documentation for the latest integration options. In practice, many teams using Codex alongside MCP-enabled tools handle tool connections at the orchestration layer rather than within Codex directly.
Cursor
Cursor reads .cursorrules for agent behavior instructions. The most portable approach:
- Keep your source of truth in
agents.md - Generate or sync
.cursorrulesfrom it — either manually or with a simple script - Use Cursor’s MCP settings panel to configure your MCP connections
Cursor’s MCP support has expanded significantly, making it practical to use the same MCP server definitions you use with Claude Code.
A portable project structure
A clean directory layout for a portable agent stack:
project-root/
.agent/
agents.md # Source of truth for agent behavior
skills/
search.md
github.md
test_runner.md
.mcp/
config.json # MCP server definitions
CLAUDE.md # Claude Code entry point → imports agents.md
.cursorrules # Cursor entry point → imports agents.md
Version control all of it. The .mcp/config.json should be committed without secrets — use environment variables for tokens and credentials.
Common Mistakes That Reintroduce Lock-In
Building a portable stack takes discipline. Here are the patterns that quietly reintroduce lock-in even when you’re trying to avoid it.
Hardcoding runtime-specific instructions
Adding Claude-specific instructions directly to CLAUDE.md that don’t exist in agents.md means you’ve split your source of truth. Future changes require updates in multiple places.
Fix: Keep all behavioral logic in agents.md. The runtime-specific files (CLAUDE.md, .cursorrules) should be thin wrappers that pull from the shared definition.
Using proprietary tool formats for MCP-compatible integrations
If an MCP server exists for an integration you need (GitHub, Postgres, Slack, etc.), use it instead of a tool-specific plugin. The short-term convenience of a proprietary plugin creates long-term migration work.
Storing agent context in the chat UI
It’s tempting to just paste context into a chat window rather than encoding it in agents.md. That context disappears when the session ends and doesn’t travel with your codebase.
Fix: If you find yourself typing the same context repeatedly, it belongs in agents.md.
Missing environment portability
Your MCP config might work perfectly on your machine and break for every teammate because credentials are hardcoded or paths are absolute.
Fix: Use environment variable references in config files, and document required variables in your README or a .env.example file.
How MindStudio Fits Into a Portable Agent Stack
One practical challenge with portable agent stacks is that writing your own MCP servers and skill implementations for every capability you need is genuinely tedious. Rate limiting, auth, retries, error handling — it’s a lot of infrastructure for what should be a simple “send an email” or “search the web” call.
This is where MindStudio’s Agent Skills Plugin is worth knowing about. It’s an npm SDK (@mindstudio-ai/agent) that exposes 120+ typed capabilities as simple method calls any agent can invoke — including Claude Code, LangChain, and CrewAI.
import { MindStudio } from '@mindstudio-ai/agent';
const agent = new MindStudio();
// Search the web
const results = await agent.searchGoogle({ query: 'MCP server examples' });
// Send email
await agent.sendEmail({ to: 'team@company.com', subject: '...', body: '...' });
// Generate an image
const image = await agent.generateImage({ prompt: '...' });
Because it’s a standard npm package, it works in any JavaScript/TypeScript agent — not just MindStudio’s own builder. It handles the infrastructure layer (retries, rate limiting, auth) so your agent code stays focused on reasoning.
From a portability standpoint, this is a clean way to define skills that aren’t tied to any specific runtime. The same agent.searchGoogle() call works whether you’re running the agent through Claude Code, a custom Node.js script, or an orchestration framework like LangChain.
MindStudio also supports agentic MCP servers — meaning you can expose MindStudio workflows as MCP tools that any MCP-compatible client can call. If your team builds workflows in MindStudio (AI-powered data enrichment, document processing, customer lookup), those workflows become part of your portable tool layer rather than isolated automations.
You can try MindStudio free at mindstudio.ai.
FAQ
What is agents.md and why should I use it?
agents.md is a markdown file convention for defining AI agent behavior in a runtime-agnostic format. Instead of encoding agent instructions inside a specific tool’s proprietary configuration, you write them once in a plain text file that any agent runtime can consume. It makes your agent setup portable, version-controllable, and easier to maintain across tools like Claude Code, Cursor, and others.
What is the Model Context Protocol (MCP)?
MCP is an open standard for connecting AI models to external tools and data sources. It defines a client-server protocol where MCP servers expose capabilities (filesystem access, database queries, API calls) and MCP clients (agent runtimes) connect to them. Because it’s an open standard, an MCP server you build works with any MCP-compatible client — you’re not building a Claude plugin or a Cursor plugin, you’re building an MCP server.
How do I avoid vendor lock-in when building AI agents?
The core strategy is separating your agent’s identity, capabilities, and tool connections from any specific runtime:
- Define behavior in
agents.md, not inside a tool’s proprietary config - Document capabilities in
skill.mdfiles with clear input/output contracts - Use MCP for tool connections wherever possible
- Keep runtime-specific files (CLAUDE.md, .cursorrules) as thin wrappers that reference your shared definitions
Does Cursor support MCP?
Yes, Cursor supports MCP and has a built-in configuration panel for connecting MCP servers. This means MCP server configurations you write for Claude Code can also be used in Cursor, which is a meaningful step toward a genuinely portable tool layer.
How is skill.md different from agents.md?
agents.md describes the agent as a whole — its purpose, constraints, context, and overall behavior. skill.md (or individual skill files) describe discrete capabilities the agent can invoke, with explicit input/output contracts. Think of agents.md as the job description and skill.md files as the tool manual.
Can I use this approach with AI orchestration frameworks like LangChain or CrewAI?
Yes. agents.md and skill.md are just files — any system that can read text can consume them. LangChain agents can be initialized with the contents of agents.md as their system context, and skill definitions can inform how you structure tools in LangChain’s Tool abstraction. For MCP specifically, check each framework’s current documentation for native MCP support; it’s growing quickly across the ecosystem.
Key Takeaways
- Separate the layers: Agent behavior, skill definitions, and tool connections should live in different files, each independently maintainable.
- Use open files as your source of truth:
agents.mdandskill.mdin your repo beat proprietary dashboard configs for portability and version control. - MCP is your best bet for tool portability: Any integration you build as an MCP server works across Claude Code, Cursor, and other compliant runtimes without rewriting.
- Runtime-specific files should be thin wrappers:
CLAUDE.mdand.cursorrulesare entry points, not the actual agent definition. - Discipline matters: Lock-in creeps back in through convenience — hardcoded instructions, proprietary plugins, chat-window context that never gets encoded properly.
Building a portable stack takes slightly more upfront discipline than just using whatever a tool gives you by default. But when your team adds a new runtime, or a better model becomes available, or you need to run the same agent in a different context — you’ll be glad the logic was never locked into one place to begin with.
If you want to reduce the infrastructure overhead of building out your skill layer, MindStudio is worth exploring — both the Agent Skills Plugin for developer teams and the no-code builder for teams that want to create and expose agent capabilities without writing server code.



