Skip to content

Conversation

@vlobachev
Copy link
Owner

@vlobachev vlobachev commented Jan 20, 2026

User description

Motivation

  • Bring the Vibecode Blueprint up to 2025–2026 agentic best practices by making AGENTS.md the canonical, cross-tool agent interface and adding minimal integrations for modern coding agents (Copilot, Claude Code, Cline, etc.).
  • Provide a local, minimal MCP memory server reference so agents can persist and query project memory during interactive agent loops without heavy dependencies.
  • Make generator output testable and reproducible via golden snapshots so agent-driven template changes are detectable and reviewable.
  • Improve onboarding and multi-agent coordination with concise guides, checklist templates, and per-package AGENTS.md plumbs.

Description

  • Make AGENTS.md canonical and AGENTS-first: replaced/streamlined root AGENTS.md and added guidance that tool-specific files must reference it; added pointer docs in docs/guides/AGENTS_AND_TOOL_RULES.md and updated CLAUDE.md and templates to defer to AGENTS.md.
  • Add a minimal MCP reference implementation under src/mcp-memory/ with a file-backed JSON MemoryStore and an HTTP JSON-RPC (MCP-style) server exposing add_memory, search_memory, summarize_memory, resources/list, and resources/read.
  • Generator & templates: add per-package AGENTS.md.hbs templates, conditional generation fixes (skip packages when not selected), expose format:check in generated package.json templates, and add VIBECODE_TEST_YEAR support for deterministic test runs.
  • Validation and developer UX: add src/validate.js (runs lint, format:check, test), package.json scripts (format:check, mcp-memory), .eslintrc.cjs (basic ESLint config), and GitHub Copilot / PR templates plus an agent task checklist template for multi-agent coordination.
  • Tests & examples: add unit tests for the MemoryStore, an integration test for the MCP server, a generator golden test that snapshots generated files (tests/setup/generator-golden.test.js + tests/golden/setup-output.snapshot.json), and a small contract-first example demonstrating a contract test pattern.

Testing

  • Ran the test suite: pnpm test (runs Node.js built-in tests under tests/), which executed the MCP MemoryStore unit tests, MCP server integration test, and generator golden test; all tests passed locally (4 tests, 0 failures).
  • Verified deterministic generator output by running the deterministic test-runner node src/test-setup.js (used by generator golden test) and refreshed the golden snapshot at tests/golden/setup-output.snapshot.json to lock expected scaffold hashes.
  • Validation entrypoint added: node src/validate.js (invoked by make validate) which runs pnpm run lint, pnpm run format:check, and pnpm test — this command was exercised during development and the test step passed.

Commands to validate locally

  • Install: pnpm install or make install
  • Run generator test once: pnpm run test-setup (deterministic generator run)
  • Run tests: pnpm test
  • Run full validation: make validate or node src/validate.js (runs lint + format check + tests)

Files/areas touched (high level)

  • AGENTS.md, CLAUDE.md, README.md, docs/ (new guides)
  • src/mcp-memory/* (memory store + server)
  • src/validate.js, src/setup.js, src/test-setup.js
  • templates/* (AGENTS templates, package.json.hbs updates)
  • tests/mcp-memory/*, tests/setup/generator-golden.test.js, tests/golden/setup-output.snapshot.json

All automated tests included in pnpm test passed locally.


Codex Task


PR Type

Enhancement, Tests, Documentation


Description

  • Modernize AGENTS.md as canonical, cross-tool agent interface for 2025–2026 agentic workflows

  • Add minimal MCP memory reference server with file-backed JSON storage and HTTP JSON-RPC interface

  • Implement generator golden tests and per-package AGENTS.md templates for reproducible scaffolding

  • Add validation entrypoint, ESLint config, GitHub templates, and MCP/Copilot/Claude guides


Diagram Walkthrough

flowchart LR
  A["AGENTS.md<br/>Canonical Rules"] --> B["Tool-Specific Files<br/>Claude/Copilot/Cline"]
  A --> C["Generator<br/>Templates"]
  C --> D["Per-Package<br/>AGENTS.md"]
  E["MCP Memory Server<br/>JSON-RPC HTTP"] --> F["Agent Workflows<br/>Persistent Context"]
  G["Generator Golden Test<br/>Snapshot Hashes"] --> H["Deterministic<br/>Output Validation"]
  I["Validation Script<br/>lint+format+test"] --> J["CI/CD Integration"]
Loading

File Walkthrough

Relevant files
Documentation
29 files
AGENTS.md
Refactor to canonical, concise agent interface                     
+96/-277
CLAUDE.md
Simplify to pointer-based Claude guidance                               
+29/-102
AGENTS.md.hbs
Streamline generated AGENTS.md for clarity                             
+71/-146
CLAUDE.md.hbs
Simplify generated Claude guidance                                             
+36/-111
README.md.hbs
Document format:check command                                                       
+1/-0     
PROJECT_STRUCTURE.md.hbs
Add per-package AGENTS.md to structure                                     
+1/-0     
AGENTS.md.hbs
Create package-level API agent guidance                                   
+19/-0   
AGENTS.md.hbs
Create package-level CLI agent guidance                                   
+19/-0   
AGENTS.md.hbs
Create package-level core agent guidance                                 
+19/-0   
AGENTS.md.hbs
Create package-level types agent guidance                               
+19/-0   
AGENTS.md.hbs
Create package-level web agent guidance                                   
+19/-0   
agent-task.md
Add agent task issue template                                                       
+25/-0   
copilot-instructions.md
Add GitHub Copilot agent mode instructions                             
+16/-0   
pull_request_template.md
Add PR template with agent checklist                                         
+14/-0   
calculator.js
Add contract-first example implementation                               
+15/-0   
contract.test.js
Add contract test example                                                               
+16/-0   
AGENTS_AND_TOOL_RULES.md
Document AGENTS.md canonical alignment                                     
+35/-0   
CLAUDE_CODE.md
Add Claude Code usage guide                                                           
+27/-0   
COPILOT_AGENT_MODE.md
Add Copilot agent mode guide                                                         
+42/-0   
MCP.md
Add MCP memory server usage guide                                               
+80/-0   
ONBOARDING_30_MINUTES.md
Add fast-track onboarding guide                                                   
+40/-0   
AGENT_TASK_CHECKLIST.md
Add agent task coordination checklist                                       
+44/-0   
MCP_MEMORY_IMPLEMENTATION.md
Update with reference MVP implementation                                 
+30/-34 
PROJECT_STRUCTURE.md
Update structure with new guides and tests                             
+33/-16 
README.md
Update documentation index                                                             
+17/-5   
README.md
Add contract-first example reference                                         
+6/-5     
README.md
Add contract-first pattern explanation                                     
+12/-0   
README.md
Add tool support and documentation links                                 
+7/-0     
README.md
Document generator output snapshots                                           
+10/-0   
Enhancement
6 files
package.json.hbs
Add format:check and mcp-memory scripts                                   
+1/-0     
memory-store.js
Implement file-backed JSON memory store                                   
+89/-0   
server.js
Implement HTTP JSON-RPC MCP server                                             
+230/-0 
test-setup.js
Add VIBECODE_TEST_YEAR support for determinism                     
+12/-1   
validate.js
Create validation entrypoint script                                           
+31/-0   
package.json
Add mcp-memory script and test path fix                                   
+4/-2     
Bug fix
1 files
setup.js
Skip templates for unselected packages                                     
+11/-0   
Configuration changes
1 files
.eslintrc.cjs
Add ESLint configuration                                                                 
+13/-0   
Tests
4 files
memory-store.test.js
Add unit tests for memory store                                                   
+40/-0   
server.test.js
Add integration tests for MCP server                                         
+49/-0   
generator-golden.test.js
Add golden test for generator output                                         
+68/-0   
setup-output.snapshot.json
Add generator output snapshot baseline                                     
+82/-0   

- refresh AGENTS and docs for 2025-2026 agent workflows

- add MCP memory server reference with tests

- add generator golden tests and templates

AI-Generated: Yes

Reviewed-by: N/A
@qodo-code-review
Copy link

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Documentation Structure Validation

Failed stage: Validate documentation content quality [❌]

Failed test name: ""

Failure summary:

The action failed during documentation content validation because a required section was missing:
-
AGENTS.md did not contain the required section header What You Can Do, causing the script to exit
with code 1 (Process completed with exit code 1).

There is also a post-job cleanup warning unrelated to the main failure:
- Git reported fatal: No url
found for submodule path 'sources/rules-for-ai' in .gitmodules (exit code 128) while cleaning up
submodule config, but the job had already failed due to the documentation check.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

178:  �[36;1m  �[0m
179:  �[36;1m  claude_sections=("Development Commands" "Project Architecture")�[0m
180:  �[36;1m  for section in "${claude_sections[@]}"; do�[0m
181:  �[36;1m    if ! grep -q "$section" CLAUDE.md; then�[0m
182:  �[36;1m      echo "❌ CLAUDE.md missing required section: $section"�[0m
183:  �[36;1m      exit 1�[0m
184:  �[36;1m    fi�[0m
185:  �[36;1m  done�[0m
186:  �[36;1mfi�[0m
187:  �[36;1m�[0m
188:  �[36;1mecho "✅ Documentation content validation passed"�[0m
189:  shell: /usr/bin/bash -e {0}
190:  ##[endgroup]
191:  Validating documentation content quality...
192:  ❌ AGENTS.md missing required section: What You Can Do
193:  ##[error]Process completed with exit code 1.
194:  Post job cleanup.
195:  [command]/usr/bin/git version
196:  git version 2.52.0
197:  Temporarily overriding HOME='/home/runner/work/_temp/7cc044fb-5585-41a6-880a-c9d5cc7317f2' before making global git config changes
198:  Adding repository directory to the temporary git global config as a safe directory
199:  [command]/usr/bin/git config --global --add safe.directory /home/runner/work/vibecode/vibecode
200:  [command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand
201:  [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :"
202:  fatal: No url found for submodule path 'sources/rules-for-ai' in .gitmodules
203:  ##[warning]The process '/usr/bin/git' failed with exit code 128
204:  Cleaning up orphan processes

@qodo-code-review
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🔴
Unbounded request body

Description: The request body is accumulated into an unbounded string via req.on('data') without any
size limit, enabling a trivial memory-exhaustion denial-of-service by sending a very large
POST payload.
server.js [190-210]

Referred Code
const server = http.createServer(async (req, res) => {
  if (req.method !== 'POST') {
    res.writeHead(405, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ error: 'Only POST is supported' }));
    return;
  }

  let body = '';
  req.on('data', (chunk) => {
    body += chunk;
  });
  req.on('end', async () => {
    try {
      const payload = JSON.parse(body || '{}');
      await store.initialize();
      const response = await handleRpc(payload, store);
      jsonResponse(res, response);
    } catch (error) {
      jsonResponse(res, jsonError(null, error?.message || 'Invalid JSON', -32700));
    }
  });
Unauthenticated RPC access

Description: The MCP JSON-RPC server exposes state-changing and data-reading methods (tools/call for
add_memory and resources/read) over HTTP with no authentication/authorization, so if the
process is bound to a non-loopback interface (e.g., via MCP_MEMORY_HOST) or reachable via
port-forwarding, any requester could write/read project “memory” content.
server.js [4-210]

Referred Code
const DEFAULT_HOST = process.env.MCP_MEMORY_HOST || '127.0.0.1';
const DEFAULT_PORT = Number.parseInt(process.env.MCP_MEMORY_PORT, 10) || 3333;
const DEFAULT_PATH = process.env.MCP_MEMORY_PATH || 'memory-bank/mcp-memory.json';

const TOOL_DEFINITIONS = [
  {
    name: 'add_memory',
    description: 'Store a memory entry with optional tags.',
    inputSchema: {
      type: 'object',
      properties: {
        title: { type: 'string' },
        content: { type: 'string' },
        tags: { type: 'array', items: { type: 'string' } }
      },
      required: ['content']
    }
  },
  {
    name: 'search_memory',
    description: 'Search memories by substring match.',


 ... (clipped 186 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit logging: Critical actions (e.g., add_memory, resources/read) are executed without any audit log
fields (user id, timestamp, action, outcome), preventing event reconstruction.

Referred Code
case 'resources/list': {
  const entries = await store.list();
  return {
    jsonrpc: '2.0',
    id,
    result: {
      resources: entries.map((entry) => ({
        uri: memoryUri(entry.id),
        name: entry.title,
        mimeType: 'application/json'
      }))
    }
  };
}
case 'resources/read': {
  const entryId = parseMemoryId(params?.uri);
  if (!entryId) {
    return jsonError(id, 'Invalid resource URI', -32602);
  }
  const entry = await store.getById(entryId);
  if (!entry) {


 ... (clipped 64 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Missing edge checks: The HTTP handler lacks basic edge-case protections (e.g., request body size limits and
payload shape validation), which can lead to crashes or resource exhaustion on
malformed/large inputs.

Referred Code
const server = http.createServer(async (req, res) => {
  if (req.method !== 'POST') {
    res.writeHead(405, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ error: 'Only POST is supported' }));
    return;
  }

  let body = '';
  req.on('data', (chunk) => {
    body += chunk;
  });
  req.on('end', async () => {
    try {
      const payload = JSON.parse(body || '{}');
      await store.initialize();
      const response = await handleRpc(payload, store);
      jsonResponse(res, response);
    } catch (error) {
      jsonResponse(res, jsonError(null, error?.message || 'Invalid JSON', -32700));
    }
  });

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Leaks error details: JSON-RPC responses return error.message directly to callers, which can expose internal
implementation details rather than using a generic user-facing error with detailed
internal logging.

Referred Code
  } catch (error) {
    return jsonError(id, error?.message || 'Server error');
  }
}

export function createMcpServer({ host = DEFAULT_HOST, port = DEFAULT_PORT, filePath = DEFAULT_PATH } = {}) {
  const store = new MemoryStore({ filePath });

  const server = http.createServer(async (req, res) => {
    if (req.method !== 'POST') {
      res.writeHead(405, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ error: 'Only POST is supported' }));
      return;
    }

    let body = '';
    req.on('data', (chunk) => {
      body += chunk;
    });
    req.on('end', async () => {
      try {


 ... (clipped 7 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
No input validation: The server accepts arbitrary JSON-RPC payloads without validating jsonrpc, method, params
schema/types or enforcing authentication/authorization boundaries before mutating/reading
stored memory.

Referred Code
async function handleRpc(payload, store) {
  const { id, method, params } = payload;

  try {
    switch (method) {
      case 'initialize':
        return {
          jsonrpc: '2.0',
          id,
          result: {
            protocolVersion: '2024-11-05',
            capabilities: {
              resources: { list: true, read: true },
              tools: { list: true, call: true }
            },
            serverInfo: {
              name: 'vibecode-mcp-memory',
              version: '0.1.0'
            }
          }
        };


 ... (clipped 85 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Unstructured console log: The server emits an unstructured console.log startup message and there is no evident
structured logging approach for future debugging/auditing needs.

Referred Code
if (process.argv[1] === new URL(import.meta.url).pathname) {
  const instance = createMcpServer();
  instance.start().then((address) => {
    const location = typeof address === 'string' ? address : `${address.address}:${address.port}`;
    console.log(`MCP memory server listening on ${location}`);
  });

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Prevent race conditions during writes

To prevent a race condition that can cause data loss when adding entries
concurrently, wrap the read-modify-write logic in the add method with a mutex.

src/mcp-memory/memory-store.js [42-59]

+import { Mutex } from 'async-mutex';
+// ... (inside MemoryStore class)
+constructor({ filePath }) {
+  this.filePath = filePath;
+  this.writeLock = new Mutex();
+}
+// ...
 async add({ title, content, tags }) {
   if (!content || typeof content !== 'string') {
     throw new Error('content is required');
   }
   const now = new Date().toISOString();
   const entry = {
     id: crypto.randomUUID(),
     title: title || 'Untitled',
     content,
     tags: Array.isArray(tags) ? tags : [],
     createdAt: now,
     updatedAt: now
   };
-  const entries = await this.readAll();
-  entries.push(entry);
-  await this.writeAll(entries);
+
+  await this.writeLock.runExclusive(async () => {
+    const entries = await this.readAll();
+    entries.push(entry);
+    await this.writeAll(entries);
+  });
+
   return entry;
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a critical race condition in the file writing logic that could lead to data loss and proposes a standard and valid solution using a mutex.

Medium
General
Initialize the store only once

Improve performance by moving the store.initialize() call from the per-request
handler to the server's start function, so it only runs once on startup.

src/mcp-memory/server.js [187-222]

 export function createMcpServer({ host = DEFAULT_HOST, port = DEFAULT_PORT, filePath = DEFAULT_PATH } = {}) {
   const store = new MemoryStore({ filePath });
 
   const server = http.createServer(async (req, res) => {
     if (req.method !== 'POST') {
       res.writeHead(405, { 'Content-Type': 'application/json' });
       res.end(JSON.stringify({ error: 'Only POST is supported' }));
       return;
     }
 
     let body = '';
     req.on('data', (chunk) => {
       body += chunk;
     });
     req.on('end', async () => {
       try {
         const payload = JSON.parse(body || '{}');
-        await store.initialize();
         const response = await handleRpc(payload, store);
         jsonResponse(res, response);
       } catch (error) {
         jsonResponse(res, jsonError(null, error?.message || 'Invalid JSON', -32700));
       }
     });
   });
 
   return {
     server,
     start: () => new Promise((resolve) => {
-      server.listen(port, host, () => resolve(server.address()));
+      store.initialize().then(() => {
+        server.listen(port, host, () => resolve(server.address()));
+      });
     }),
     stop: () => new Promise((resolve, reject) => {
       server.close((err) => (err ? reject(err) : resolve()));
     })
   };
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out an inefficiency where store.initialize() is called on every request and proposes moving it to the server's start function, which is a valid performance improvement.

Medium
Recover from corrupt JSON store

To prevent crashes from a corrupt JSON file, wrap JSON.parse in the readAll
method within a try-catch block and restore a default state if parsing fails.

src/mcp-memory/memory-store.js [24-28]

 async readAll() {
   const raw = await fs.readFile(this.filePath, 'utf8');
-  const data = JSON.parse(raw);
+  let data;
+  try {
+    data = JSON.parse(raw);
+  } catch {
+    data = DEFAULT_DATA;
+    await fs.writeFile(this.filePath, JSON.stringify(DEFAULT_DATA, null, 2));
+  }
   return Array.isArray(data.entries) ? data.entries : [];
 }
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies that a corrupt JSON file can crash the application and proposes a reasonable error handling strategy to recover gracefully, improving the server's resilience.

Low
Improve memory URI parsing logic

Make the parseMemoryId function more robust by adding a check to ensure the
parsed ID is not an empty string, preventing potential bugs from URIs like
memory://.

src/mcp-memory/server.js [66-74]

 function parseMemoryId(uri) {
-  if (!uri || typeof uri !== 'string') {
+  if (!uri || typeof uri !== 'string' || !uri.startsWith('memory://')) {
     return null;
   }
-  if (uri.startsWith('memory://')) {
-    return uri.replace('memory://', '');
-  }
-  return null;
+  const id = uri.substring('memory://'.length);
+  return id.length > 0 ? id : null;
 }
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies that an empty ID could be parsed from a URI like memory:// and proposes a stricter validation, which improves the robustness of the URI parsing logic.

Low
Validate JSON-RPC version field

Improve JSON-RPC 2.0 compliance by adding a check in handleRpc to validate that
payload.jsonrpc is '2.0' and return an appropriate error if it is not.

src/mcp-memory/server.js [76-80]

 async function handleRpc(payload, store) {
-  const { id, method, params } = payload;
+  const { id, jsonrpc, method, params } = payload;
+  if (jsonrpc !== '2.0') {
+    return {
+      jsonrpc: '2.0',
+      id,
+      error: { code: -32600, message: 'Invalid JSON-RPC version' }
+    };
+  }
   try {
     switch (method) {
       // ...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly points out a missing validation for the JSON-RPC version, and adding this check makes the server more compliant with the JSON-RPC 2.0 specification.

Low
Sanitize and clamp limit parameter

Sanitize the limit parameter in the search method by coercing it to a positive
integer to prevent unexpected slicing behavior from invalid inputs.

src/mcp-memory/memory-store.js [66-79]

 async search({ query, limit = 10 }) {
   const entries = await this.readAll();
+  const max = Number.isInteger(limit) && limit > 0 ? limit : 10;
   if (!query) {
-    return entries.slice(-limit);
+    return entries.slice(-max);
   }
   const normalized = query.toLowerCase();
   const results = entries.filter(/*...*/);
-  return results.slice(0, limit);
+  return results.slice(0, max);
 }
  • Apply / Chat
Suggestion importance[1-10]: 4

__

Why: The suggestion correctly points out that the limit parameter is not validated, which could lead to unexpected behavior. Adding sanitization improves the robustness of the search method.

Low
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants