DEV Community

Cover image for Building Code Mentor: An AI Agent That Creates Learning Roadmaps Using Mastra & Telex
Queen Samuel
Queen Samuel

Posted on

Building Code Mentor: An AI Agent That Creates Learning Roadmaps Using Mastra & Telex

Ever wished you had a personal programming mentor available 24/7? That's exactly what I built with Code Mentor as my stage 3 HNG task. Code Mentor is AI agent that generates personalized learning roadmaps and project ideas for any programming language.
In this post, I'll walk you through my journey building this agent using Mastra, deploying it to the cloud, and integrating it with Telex using the Agent-to-Agent (A2A) protocol.

The Goal
Create a simple, focused AI agent that:

Generates structured learning roadmaps tailored to experience level
Suggests practical projects to build
Provides tips and resources
Works seamlessly in a team workspace (Telex)

Key constraint: Keep it simple, no feature creep, no debugging, just roadmaps and projects.

Tech Stack

Mastra - AI agent framework with A2A protocol support
Gemini 2.0 Flash - Google's latest LLM (fast and free tier!)
A2A Protocol - Standard for agent-to-agent communication
Telex.im - Team collaboration platform for AI agents

Part 1: Setting Up Mastra
Installation
Getting started with Mastra is surprisingly easy:

npm create mastra@latest -y
cd code-mentor
npm install
Enter fullscreen mode Exit fullscreen mode

Setting Up Environment
I chose Gemini 2.0 Flash because:

✅ Free tier is generous
✅ Fast responses
✅ Great for conversational AI

The Agent Definition
Here's what surprised me: you don't need tools for content generation. The LLM is smart enough on its own!

// src/agents/code-mentor.ts
import { Agent } from '@mastra/core/agent';
import { Memory } from '@mastra/memory';
import { LibSQLStore } from '@mastra/libsql';

export const codeMentor = new Agent({
  name: 'code-mentor',
  description: 'Provides learning roadmaps and project ideas',
  instructions: `You are Code Mentor - a friendly programming learning guide.

  Your role:
  1. Create personalized learning roadmaps (6-8 phases)
  2. Suggest practical projects (4-6 projects)
  3. Provide tips and resources

  When users greet you:
  - Introduce yourself warmly
  - Explain what you do
  - Ask what they want to learn

  When creating roadmaps:
  - Tailor to their experience level
  - Use clear formatting with emojis
  - Include project ideas
  - Be encouraging!

  What you DON'T do:
  - Debug code
  - Fix errors
  - Write code for users`,

  model: 'google/gemini-2.0-flash',
  memory: new Memory({
    storage: new LibSQLStore({
      url: 'file:../mastra.db',
    }),
  }),
});
Enter fullscreen mode Exit fullscreen mode

Key Lessons Learned

  1. Instructions Matter - A LOT Initially, my agent was too generic. I learned to:

Be specific about formatting (use emojis, numbered lists)
Define clear boundaries (what it does AND doesn't do)
Include example interactions
Tell it to check conversation history

  1. Memory is Built-In Mastra's memory system automatically:

Stores conversation history
Maintains context across turns
Allows the agent to reference previous messages

This was huge! No custom implementation needed.

  1. Tools Are Optional My first version had a generateLearningPlanTool that returned hardcoded data. Big mistake! I learned: If the LLM can generate it, skip the tool. Tools are for:

External API calls
Database queries
Complex calculations
Code execution

Part 3: The A2A Protocol
This is where things got interesting. The A2A (Agent-to-Agent) protocol is a JSON-RPC 2.0 standard that lets agents talk to each other.
Creating the A2A Route Handler

// src/routes/a2a-agent.ts
import { registerApiRoute } from '@mastra/core/server';
import { randomUUID } from 'crypto';

export const a2aAgentRoute = registerApiRoute('/a2a/agent/:agentId', {
  method: 'POST',
  handler: async (c) => {
    const mastra = c.get('mastra');
    const agentId = c.req.param('agentId');
    const body = await c.req.json();

    const { jsonrpc, id: requestId, method, params } = body;

    // Validate JSON-RPC 2.0
    if (jsonrpc !== '2.0' || !requestId) {
      return c.json({
        jsonrpc: '2.0',
        id: requestId || null,
        error: { code: -32600, message: 'Invalid Request' }
      }, 400);
    }

    const agent = mastra.getAgent(agentId);
    if (!agent) {
      return c.json({
        jsonrpc: '2.0',
        id: requestId,
        error: { code: -32602, message: `Agent not found` }
      }, 404);
    }

    // Extract messages from params
    const { message, messages } = params || {};
    let messagesList = message ? [message] : messages || [];

    // Convert A2A messages to Mastra format
    const mastraMessages = messagesList.map((msg) => ({
      role: msg.role,
      content: msg.parts?.map((part) => {
        if (part.kind === 'text') return part.text;
        if (part.kind === 'data') return JSON.stringify(part.data);
        return '';
      }).join('\n') || ''
    }));

    // Execute agent
    const response = await agent.generate(mastraMessages);
    const agentText = response.text || '';

    // Return A2A-compliant response
    return c.json({
      jsonrpc: '2.0',
      id: requestId,
      result: {
        id: randomUUID(),
        status: {
          state: 'completed',
          message: {
            role: 'agent',
            parts: [{ kind: 'text', text: agentText }]
          }
        },
        artifacts: [
          {
            artifactId: randomUUID(),
            name: `${agentId}Response`,
            parts: [{ kind: 'text', text: agentText }]
          }
        ]
      }
    });
  }
});
Enter fullscreen mode Exit fullscreen mode

Registering the Route

// src/mastra/index.ts
import { Mastra } from '@mastra/core/mastra';
import { codeMentor } from '../agents/code-mentor';
import { a2aAgentRoute } from '../routes/a2a-agent';

export const mastra = new Mastra({
  agents: { codeMentor },
  server: {
    apiRoutes: [a2aAgentRoute]
  }
});
Enter fullscreen mode Exit fullscreen mode

Part 4: Deployment
Testing Locally
First, test everything locally:
Visit http://localhost:4111 for the Mastra playground. Test your agent with:

Simple greetings
Learning requests
Follow-up questions

Deploying to Mastra Cloud
Once testing looked good:

Login

mastra auth login

Deploy

mastra deploy

You get an A2A endpoint like:
https://code-mentor-xyz.mastra.cloud/a2a/agent/codeMentor
Pro tip: Test this endpoint with Postman before integrating with Telex!
Part 5: Telex Integration
Creating the Workflow JSON

{
  "active": true,
  "category": "education",
  "description": "AI agent that provides learning roadmaps",
  "name": "Code Mentor",
  "nodes": [
    {
      "id": "code_mentor_agent",
      "name": "Code Mentor Agent",
      "type": "a2a/mastra-a2a-node",
      "url": "https://code-mentor-xyz.mastra.cloud/a2a/agent/codeMentor"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Importing to Telex

Go to Telex workspace
Navigate to AI Co-Workers
Import the JSON file
Activate the workflow

Using in Telex

@Code Mentor I want to learn Python

Hey Code Mentor, what projects should I build as a JavaScript beginner?
Enter fullscreen mode Exit fullscreen mode

What Worked Really Well
✅ Mastra's scaffolding - Everything you need out of the box
✅ Gemini 2.0 Flash - Fast, free, and smart enough
✅ Built-in memory - No custom implementation needed
✅ A2A protocol - Standardized agent communication
✅ Simple deployment - One command to production
What Didn't Work (And How I Fixed It)
❌ Problem: Scope Creep
Initially: Wanted to add debugging, code review, etc.
Result: Complicated instructions, confusing responses.
Fix: Focused on ONE thing: roadmaps + projects. Added clear "what I don't do" in instructions.
❌ Problem: Generic Responses
Initially: Agent gave bland, generic roadmaps.
Result: Not very useful.
Fix:

Added personality to instructions
Specified exact formatting (emojis, headers)
Included example structures
Emphasized tailoring to experience level

Key Takeaways

Start Simple - Build the core feature first, add complexity later
Instructions Are Everything - Spend time crafting clear, specific instructions
Tools Aren't Always Needed - If the LLM can do it, skip the tool
Test Early, Test Often - Use Mastra playground and Postman before deploying
The A2A Protocol Is Powerful - Standardization makes integration easy

Resources
Mastra Docs: https://mastra.ai/docs
Telex Platform: https://telex.im

Have questions or suggestions? Drop them in the comments! 👇

Top comments (0)