Dev.to AI ๐Ÿค– Ai ๐Ÿ‘ 0 ๐Ÿ“– 12 min read

The Agentic Developer Stack in 2026: Memory, Skills, MCP, and Lock-In-Free Workflows

Originally published on tamiz.pro. By 2026, the agentic developer stack has crystallized around three composable layers: persistent memory, declarative skills, and the Model Context Protocol (MCP). But the tools that im

Originally published on tamiz.pro.

By 2026, the agentic developer stack has crystallized around three composable layers: persistent memory, declarative skills, and the Model Context Protocol (MCP). But the tools that implement these layers โ€” Claude Code, Codex, and Cursor โ€” each ship their own opinionated config format. The result is a subtle lock-in trap: your workflow works beautifully inside one agent, but the moment you switch, your context, capabilities, and integrations vanish. This article dissects the anatomy of the modern agentic stack and shows you how to build a genuinely lock-in-free workflow that treats your agents as interchangeable runtimes over a shared, open substrate.

  • 1. The Anatomy of an Agentic Developer Stack
  • 2. Memory: The Persistent Context Layer
  • 3. Skills: Declarative Capability Injection
  • 4. MCP: The Universal Integration Protocol
  • 5. Headless Agents: Claude Code vs Codex vs Cursor
  • 6. Building a Lock-In-Free Workflow
  • 7. Trade-offs and the Path Forward
  • Frequently Asked Questions

1. The Anatomy of an Agentic Developer Stack

The 2026 agentic stack is not a single product โ€” it's a layered architecture where each layer has a clear responsibility. Understanding these layers is the first step to escaping lock-in, because it tells you what you can abstract and what you can't.

The Five Layers

  1. Model layer โ€” The underlying LLM (Claude, GPT, Gemini). In 2026, this is largely a commodity. You can swap models without changing your workflow.
  2. Runtime layer โ€” The headless agent CLI (Claude Code, Codex, Cursor). This is the "operator" that reads files, runs commands, and calls the model. This is where vendor lock-in lives.
  3. Memory layer โ€” Persistent context files (CLAUDE.md, AGENTS.md, .cursor/rules). This is your project's long-term knowledge.
  4. Skills layer โ€” Declarative capability definitions (SKILL.md + scripts). These tell the agent how to do things, not just what to know.
  5. Integration layer โ€” MCP servers. These give the agent access to external tools, data sources, and APIs.

The key insight: layers 3, 4, and 5 are now open standards. Memory is just Markdown. Skills are just folders with metadata. MCP is a public protocol. Only layer 2 is proprietary โ€” and that's exactly what we need to abstract.

In 2026, the agent runtime is the new "browser." It's a thin, replaceable shell around open, portable primitives.

2. Memory: The Persistent Context Layer

Memory is what separates a one-shot chat bot from a developer agent that knows your codebase. In 2026, memory has three distinct types, and each maps to a different file:

Memory Type What it stores Typical Implementation
Episodic Session transcripts, command history, git log .git/, agent session logs
Semantic Architecture decisions, conventions, project facts CLAUDE.md, AGENTS.md, .cursor/rules
Procedural How to run tests, build, deploy, fix common issues Skills (see ยง3)

The Memory File Problem

Every major agent ships its own memory file format:

  • Claude Code reads ./CLAUDE.md (project) and ~/.claude/CLAUDE.md (global).
  • Codex reads ./AGENTS.md (project) and ~/.codex/AGENTS.md (global).
  • Cursor reads .cursor/rules/*.mdc (project) and ~/.cursor/rules/*.mdc (global).

These are all Markdown with frontmatter โ€” the formats are 95% compatible, but the frontmatter schemas differ. Here's what a cross-compatible memory file looks like:

---
# This frontmatter is read by Cursor's .mdc parser.
description: Project conventions and architecture decisions
globs: ["**/*.ts", "**/*.tsx"]
alwaysApply: true
---

# Project Conventions

## Architecture

- The app uses a layered architecture: `app/` (UI), `services/` (business logic), `lib/` (utilities).
- All API calls go through `services/api.ts` โ€” never call `fetch` directly in components.
- State management uses Zustand. No Redux.

## Commands

- **Test**: `pnpm test` (runs Vitest)
- **Lint**: `pnpm lint` (runs ESLint)
- **Build**: `pnpm build` (runs TSC + Vite)

## Gotchas

- The `Date` utility in `lib/dates.ts` assumes UTC. Always pass ISO strings.
- Never import from `../` in `app/` โ€” use the `@/` alias.

The problem: Claude Code ignores the globs and alwaysApply fields. Codex ignores the description field. Cursor ignores CLAUDE.md entirely. So a single file won't work across all three.

The Lock-In-Free Memory Strategy

The solution is a two-tier memory system:

  1. Neutral tier โ€” a single AGENTS.md (or MEMORY.md) in a standard format that all agents can read.
  2. Adapter tier โ€” thin symlinks or generated files that map the neutral tier into each agent's expected location.

Here's a concrete setup:

# Project root
mkdir -p .agentic/memory

# Neutral memory file (the source of truth)
cat > .agentic/memory/MEMORY.md << 'EOF'
# Project Knowledge Base

## Architecture
- Layered: `app/` โ†’ `services/` โ†’ `lib/`

## Commands
- `pnpm test` โ€” run Vitest
- `pnpm lint` โ€” run ESLint
EOF

# Adapters (symlinks)
ln -sf .agentic/memory/MEMORY.md CLAUDE.md
ln -sf .agentic/memory/MEMORY.md AGENTS.md
mkdir -p .cursor/rules
cat > .cursor/rules/project.mdc << 'EOF'
---
description: Project conventions
globs: ["**/*"]
alwaysApply: true
---

# Project Knowledge Base

## Architecture
- Layered: `app/` โ†’ `services/` โ†’ `lib/`

## Commands
- `pnpm test` โ€” run Vitest
- `pnpm lint` โ€” run ESLint
EOF

Now, when you update MEMORY.md, all three agents pick up the change. The .mdc file duplicates content, but you can generate it with a script (see ยง6).

Runtime Memory: Vector Store

Beyond files, 2026 agents increasingly use vector memory โ€” embeddings of past sessions, issues, and commits, retrieved via RAG. This is where MCP comes in (see ยง4). The key takeaway: your memory should live in open formats (Markdown, JSON, SQLite) that any agent can read, not in a proprietary database.

3. Skills: Declarative Capability Injection

If memory tells the agent what to know, skills tell it what to do. A skill is a self-contained unit of procedural knowledge: a folder with a SKILL.md manifest and optional scripts.

Anatomy of a Skill

my-skill/
โ”œโ”€โ”€ SKILL.md          # Manifest: name, description, triggers, usage
โ”œโ”€โ”€ scripts/
โ”‚   โ””โ”€โ”€ run.sh        # Executable logic
โ””โ”€โ”€ references/
    โ””โ”€โ”€ template.md   # Optional reference material

Here's a real-world skill for running database migrations:

---
name: db-migrate
description: Run database migrations safely
triggers:
  - "migrate"
  - "db migrate"
  - "run migrations"
---

# Database Migration Skill

Use this skill to run database migrations.

## Usage

1. Check current migration status: `pnpm db:status`
2. Run pending migrations: `pnpm db:migrate`
3. If a migration fails, roll back with `pnpm db:rollback`

## Safety Rules

- Always backup before migrating in production.
- Never run migrations on a read replica.

The agent reads this file when the user says "migrate the database" and knows exactly what commands to run. No prompt engineering needed.

The Skills Problem Across Agents

In 2026, skills are not yet a single standard:

  • Claude Code supports .claude/skills/ directories (and reads SKILL.md).
  • Codex supports .codex/skills/ directories.
  • Cursor supports .cursor/skills/ directories (and has its own .mdc rules).

But the SKILL.md format is converging. The trick is to symlink a shared skills directory into each agent's expected location:

# Project root
mkdir -p .agentic/skills/db-migrate

# Write the skill once
cat > .agentic/skills/db-migrate/SKILL.md << 'EOF'
---
name: db-migrate
description: Run database migrations safely
triggers: ["migrate", "db migrate"]
---
# Database Migration Skill
- Check status: `pnpm db:status`
- Run migrations: `pnpm db:migrate`
- Rollback: `pnpm db:rollback`
EOF

# Adapters
ln -sfn ../../.agentic/skills .claude/skills
ln -sfn ../../.agentic/skills .codex/skills
ln -sfn ../../.agentic/skills .cursor/skills

Now db-migrate is available in all three agents, from one source of truth.

Pro tip: Keep skills small and single-purpose. A skill should be a capability, not a workflow. If it takes more than 10 lines of description, split it.

4. MCP: The Universal Integration Protocol

MCP is the USB-C of agent integrations. It's a JSON-RPC 2.0 protocol that lets any agent connect to any tool, data source, or API. In 2026, MCP is the standard way to give agents access to:

  • Databases (Postgres, MySQL, SQLite)
  • Version control (GitHub, GitLab, Bitbucket)
  • Issue trackers (Jira, Linear)
  • Documentation (Confluence, Notion)
  • Internal APIs and microservices

MCP Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     stdio/HTTP     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Agent CLI  โ”‚ โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ โ”‚  MCP Server โ”‚
โ”‚ (Client)    โ”‚    JSON-RPC 2.0    โ”‚  (Tools,    โ”‚
โ”‚             โ”‚                    โ”‚   Resources,โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                    โ”‚   Prompts)  โ”‚
                                   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The protocol defines three primitives:

  • Tools โ€” callable functions the agent can invoke (e.g., query_database, create_issue).
  • Resources โ€” readable data the agent can load (e.g., a schema, a config file).
  • Prompts โ€” parameterized templates the agent can use (e.g., a code review prompt).

Writing a Minimal MCP Server

Here's a complete MCP server in TypeScript using the official @modelcontextprotocol/sdk:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "project-stats",
  version: "1.0.0",
});

server.tool(
  "count_lines",
  "Count lines of code in a file",
  { path: z.string() },
  async ({ path }) => {
    const fs = await import("node:fs/promises");
    const content = await fs.readFile(path, "utf-8");
    const lines = content.split("\n").length;
    return {
      content: [{ type: "text", text: `${path}: ${lines} lines` }],
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);

Run it with:

npx tsx server.ts

Configuring MCP Across Agents

Each agent has its own config file for MCP servers, but the format is converging on JSON:

Claude Code (~/.claude.json or .mcp.json):

{
  "mcpServers": {
    "project-stats": {
      "command": "npx",
      "args": ["tsx", "/path/to/server.ts"]
    }
  }
}

Codex (~/.codex/config.toml):

[mcp_servers.project-stats]
command = "npx"
args = ["tsx", "/path/to/server.ts"]

Cursor (~/.cursor/mcp.json):

{
  "mcpServers": {
    "project-stats": {
      "command": "npx",
      "args": ["tsx", "/path/to/server.ts"]
    }
  }
}

The JSON formats for Claude and Cursor are identical. Codex uses TOML. The lock-in-free approach: store your MCP server definitions in a neutral JSON file, then generate the agent-specific configs.

5. Headless Agents: Claude Code vs Codex vs Cursor

The runtime layer is where the real differences lie. Here's a comparison of the three major headless coding agents in 2026:

Feature Claude Code (claude) Codex (codex) Cursor (cursor-agent)
Config file ~/.claude.json, .claude/ ~/.codex/config.toml ~/.cursor/mcp.json, .cursor/
Memory file CLAUDE.md AGENTS.md .cursor/rules/*.mdc
Skills dir .claude/skills/ .codex/skills/ .cursor/skills/
MCP config .mcp.json (JSON) ~/.codex/config.toml (TOML) ~/.cursor/mcp.json (JSON)
Model access Claude API OpenAI + others Any (via proxy)
Headless mode claude -p "prompt" codex exec "prompt" cursor-agent -p "prompt"
Non-interactive โœ… โœ… โœ…
Git integration Native Native Via MCP

Key Differences

  • Config formats: Claude and Cursor use JSON; Codex uses TOML. This is the biggest friction point for a unified workflow.
  • Memory: Claude and Codex both use a single Markdown file at project root. Cursor uses .mdc files with frontmatter.
  • Skills: All three now support SKILL.md directories, but the loading paths differ.
  • MCP: Claude and Cursor use identical JSON. Codex uses TOML with a different structure.

The good news: the underlying concepts are identical. The differences are purely in file paths and serialization formats. That's exactly what a lock-in-free workflow should abstract.

6. Building a Lock-In-Free Workflow

Now we get to the practical part. The goal: one shared configuration, three interchangeable agents.

The Directory Layout

~/.agentic/                    # Global, cross-project config
โ”œโ”€โ”€ memory/
โ”‚   โ””โ”€โ”€ GLOBAL.md              # Global memory (read by all agents)
โ”œโ”€โ”€ skills/
โ”‚   โ””โ”€โ”€ db-migrate/
โ”‚       โ””โ”€โ”€ SKILL.md
โ”œโ”€โ”€ mcp/
โ”‚   โ””โ”€โ”€ servers.json           # Neutral MCP server definitions
โ””โ”€โ”€ bin/
    โ””โ”€โ”€ agentic                # Wrapper script

./project/                     # Your project
โ”œโ”€โ”€ .agentic/
โ”‚   โ”œโ”€โ”€ memory/
โ”‚   โ”‚   โ””โ”€โ”€ MEMORY.md          # Project memory (source of truth)
โ”‚   โ”œโ”€โ”€ skills/
โ”‚   โ”‚   โ””โ”€โ”€ test-runner/
โ”‚   โ”‚       โ””โ”€โ”€ SKILL.md
โ”‚   โ””โ”€โ”€ mcp/
โ”‚       โ””โ”€โ”€ project-servers.json
โ”œโ”€โ”€ CLAUDE.md                  # Symlink โ†’ .agentic/memory/MEMORY.md
โ”œโ”€โ”€ AGENTS.md                  # Symlink โ†’ .agentic/memory/MEMORY.md
โ”œโ”€โ”€ .cursor/
โ”‚   โ”œโ”€โ”€ rules/
โ”‚   โ”‚   โ””โ”€โ”€ project.mdc        # Generated from MEMORY.md
โ”‚   โ””โ”€โ”€ skills/                # Symlink โ†’ .agentic/skills
โ””โ”€โ”€ .mcp.json                  # Generated from .agentic/mcp/project-servers.json

The Neutral Config Format

Create a single JSON file that defines everything in an agent-agnostic way:

{
  "memory": {
    "global": "~/.agentic/memory/GLOBAL.md",
    "project": ".agentic/memory/MEMORY.md"
  },
  "skills": {
    "dirs": [".agentic/skills", "~/.agentic/skills"]
  },
  "mcpServers": {
    "project-stats": {
      "command": "npx",
      "args": ["tsx", "/path/to/server.ts"],
      "env": { "DATABASE_URL": "postgres://localhost:5432/dev" }
    }
  }
}

The Wrapper Script

Here's a bash script that reads this config and invokes the agent you choose, with the right flags and config injection:

#!/usr/bin/env bash
# ~/.agentic/bin/agentic
set -euo pipefail

AGENT="${1:-claude}"   # claude | codex | cursor
shift || true

# Load neutral config
CONFIG="${AGENTIC_CONFIG:-./.agentic/config.json}"
MEMORY_FILE=$(jq -r '.memory.project' "$CONFIG")
SKILL_DIRS=$(jq -r '.skills.dirs | join(":")' "$CONFIG")

case "$AGENT" in
  claude)
    # Claude Code: CLAUDE.md is already a symlink
    exec claude "$@"
    ;;
  codex)
    # Codex: AGENTS.md is already a symlink
    exec codex exec "$@"
    ;;
  cursor)
    # Cursor: needs .cursor/rules generated
    # (We regenerate on every invocation to keep it fresh)
    generate_cursor_rules "$MEMORY_FILE"
    exec cursor-agent "$@"
    ;;
  *)
    echo "Unknown agent: $AGENT" >&2
    exit 1
    ;;
esac

The generate_cursor_rules function converts the neutral Markdown into a .mdc file:

generate_cursor_rules() {
  local memory_file="$1"
  mkdir -p .cursor/rules
  {
    echo "---"
    echo "description: Project knowledge"
    echo "globs: [\"**/*\"]"
    echo "alwaysApply: true"
    echo "---"
    echo ""
    cat "$memory_file"
  } > .cursor/rules/project.mdc
}

Generating Agent Configs from the Neutral Format

You can also write a one-time setup script that generates all agent-specific configs from config.json:

#!/usr/bin/env bash
# setup.sh โ€” run once per project
set -euo pipefail

CONFIG="./.agentic/config.json"

# 1. Symlink memory files
ln -sf .agentic/memory/MEMORY.md CLAUDE.md
ln -sf .agentic/memory/MEMORY.md AGENTS.md

# 2. Symlink skills
ln -sfn ../../.agentic/skills .claude/skills
ln -sfn ../../.agentic/skills .codex/skills
ln -sfn ../../.agentic/skills .cursor/skills

# 3. Generate .mcp.json (Claude + Cursor)
jq '{mcpServers: .mcpServers}' "$CONFIG" > .mcp.json

# 4. Generate Codex TOML
jq -r '.mcpServers | to_entries[] | "[mcp_servers.\(.key)]\ncommand = \"\(.value.command)\"\nargs = [\"\(.value.args | join(\"\", \"\"))\"]\n"' "$CONFIG" > ~/.codex/config.toml

Using the Workflow

# Run any agent with the same context
agentic claude "Explain the architecture"
agentic codex "Fix the failing test"
agentic cursor "Refactor the API layer"

# Or invoke directly โ€” memory and skills are already in place
claude "What's the build command?"
codex exec "Run migrations"
cursor-agent "Lint the codebase"

The beauty: you can switch agents mid-project without losing context. Your memory, skills, and MCP servers all live in open formats. The only thing you lose is the agent-specific session history โ€” which is a small price for portability.

7. Trade-offs and the Path Forward

What You Gain

  • Portability: Switch agents in seconds, not days.
  • Longevity: When a new agent launches (or an old one dies), your workflow survives.
  • Transparency: Your project's knowledge lives in plain Markdown, not a proprietary DB.
  • Composability: MCP servers and skills are reusable across agents.

What You Pay

  • Abstraction overhead: You maintain symlinks and generation scripts.
  • Feature loss: Some agent-specific features (e.g., Claude's subagents, Cursor's tab autocomplete) don't port.
  • Performance: Symlinks and file generation add milliseconds โ€” negligible in practice.
  • Frontmatter drift: Cursor's .mdc needs globs and alwaysApply; other agents ignore them.

The Path Forward

The industry is converging on standards. MCP is already a de facto standard. Skills are heading toward a shared SKILL.md format. Memory files are converging on a single Markdown convention. By late 2026, expect:

  • A unified memory file spec (probably AGENTS.md wins).
  • MCP as the universal integration layer (already true).
  • Skills standardized via MCP resources (skills become MCP resources, not separate dirs).
  • A single config format (JSON, likely).

Until then, the lock-in-free workflow above is your best defense.

Frequently Asked Questions

Q: Do I really need to maintain symlinks for every agent?
A: Not necessarily. If you only use one agent, skip the symlinks. The workflow pays off when you switch agents or want to future-proof your setup. For most teams, the setup script in ยง6 automates everything.

Q: What about agent-specific features like Claude's subagents or Cursor's tab completion?
A: These are runtime features, not context features. They don't affect your memory, skills, or MCP config. You lose them when switching agents, but your project knowledge carries over. If you need a specific feature, you can always invoke that agent directly for that task.

Q: How do I handle secrets and environment variables across agents?
A: Use MCP server env fields, which are defined in your neutral config.json. Never hardcode secrets in memory files or skills. Use .env files or a secret manager, and reference them in the MCP config.

๐Ÿ“ฐ Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes โ€” full credit and traffic to the original publisher.