-
Notifications
You must be signed in to change notification settings - Fork 4
First Agent Tutorial
Interactive tutorial to create and interact with your first aistack agent.
- How to spawn an agent using MCP tools
- How to execute tasks with an agent
- How to use memory to share context
- How to coordinate multiple agents
- Best practices for agent interaction
- aistack installed and configured
- Claude Code with MCP integration enabled
- API key configured (Anthropic, OpenAI, or Ollama)
See Installation and Configuration Guide if you haven't set these up.
In Claude Code, use the agent_spawn MCP tool:
Please spawn a coder agent named "my-first-coder"
Claude Code will call:
{
"tool": "agent_spawn",
"arguments": {
"type": "coder",
"name": "my-first-coder"
}
}Expected Response:
{
"success": true,
"agent": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "coder",
"name": "my-first-coder",
"status": "idle",
"createdAt": "2026-01-27T10:30:00.000Z"
},
"prompt": "You are an expert software developer..."
}npx @blackms/aistack agent spawn -t coder -n my-first-coderimport { spawnAgent } from '@blackms/aistack';
const agent = spawnAgent('coder', {
name: 'my-first-coder'
});
console.log('Agent spawned:', agent.id);List all active agents
Response will include your agent:
{
"agents": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "coder",
"name": "my-first-coder",
"status": "idle"
}
]
}Using agent "my-first-coder", write a TypeScript function that prints "Hello, World!"
The agent will:
- Understand the requirement
- Write clean TypeScript code
- Return the implementation
Expected Output:
/**
* Prints "Hello, World!" to the console
*/
export function helloWorld(): void {
console.log("Hello, World!");
}
// Usage example
helloWorld();- Claude Code receives your request
- MCP Server routes to the coder agent
- Coder Agent generates code using configured LLM
- Response is returned through MCP to Claude Code
Store in memory with key "typescript:hello-world" the pattern we just created
This calls memory_store:
{
"tool": "memory_store",
"arguments": {
"key": "typescript:hello-world",
"content": "export function helloWorld(): void { console.log('Hello, World!'); }",
"namespace": "patterns",
"metadata": {
"language": "typescript",
"category": "basics"
}
}
}Search memory for "hello world" examples
This calls memory_search:
{
"tool": "memory_search",
"arguments": {
"query": "hello world",
"namespace": "patterns",
"limit": 5
}
}Response:
{
"count": 1,
"results": [
{
"entry": {
"key": "typescript:hello-world",
"content": "export function helloWorld()...",
"namespace": "patterns"
},
"score": 0.95,
"matchType": "fts"
}
]
}Spawn a tester agent named "my-tester"
Using agent "my-tester", create tests for the hello world function stored in memory
The tester agent will:
- Retrieve the code from memory
- Understand the functionality
- Write comprehensive tests
Expected Output:
import { describe, it, expect, vi } from 'vitest';
import { helloWorld } from './hello-world';
describe('helloWorld', () => {
it('should print "Hello, World!" to console', () => {
const consoleSpy = vi.spyOn(console, 'log');
helloWorld();
expect(consoleSpy).toHaveBeenCalledWith('Hello, World!');
expect(consoleSpy).toHaveBeenCalledTimes(1);
consoleSpy.mockRestore();
});
});Spawn a reviewer agent and have it review both the code and tests
The reviewer agent will provide feedback on:
- Code quality
- Test coverage
- Best practices
- Potential improvements
Start a new session for my Hello World project
This calls session_start:
{
"tool": "session_start",
"arguments": {
"metadata": {
"project": "hello-world-tutorial",
"goal": "Learn agent basics"
}
}
}Spawn a coder agent in session {session-id}
All agents in the same session share context and can access the same memory namespace.
End session {session-id}
This marks the session as complete and persists all data.
Let's build something more practical: a simple utility function with tests.
Spawn a coder agent named "util-coder"
Spawn a tester agent named "util-tester"
Spawn a reviewer agent named "util-reviewer"
Using "util-coder", create a TypeScript function that:
- Takes an array of numbers
- Returns the sum of all even numbers
- Handles empty arrays
- Has proper TypeScript types
Generated Code:
/**
* Calculates the sum of all even numbers in an array
* @param numbers - Array of numbers to process
* @returns Sum of even numbers, or 0 if array is empty
*/
export function sumEvenNumbers(numbers: number[]): number {
if (numbers.length === 0) {
return 0;
}
return numbers
.filter(num => num % 2 === 0)
.reduce((sum, num) => sum + num, 0);
}Using "util-tester", create comprehensive tests for the sumEvenNumbers function
Generated Tests:
import { describe, it, expect } from 'vitest';
import { sumEvenNumbers } from './sum-even-numbers';
describe('sumEvenNumbers', () => {
it('should return 0 for empty array', () => {
expect(sumEvenNumbers([])).toBe(0);
});
it('should sum even numbers correctly', () => {
expect(sumEvenNumbers([1, 2, 3, 4, 5, 6])).toBe(12); // 2 + 4 + 6
});
it('should return 0 when no even numbers present', () => {
expect(sumEvenNumbers([1, 3, 5, 7])).toBe(0);
});
it('should handle negative even numbers', () => {
expect(sumEvenNumbers([-2, -1, 0, 1, 2])).toBe(0); // -2 + 0 + 2
});
it('should handle large arrays', () => {
const largeArray = Array.from({ length: 1000 }, (_, i) => i);
const expected = Array.from({ length: 500 }, (_, i) => i * 2).reduce((a, b) => a + b, 0);
expect(sumEvenNumbers(largeArray)).toBe(expected);
});
});Using "util-reviewer", review the implementation and tests
Reviewer Feedback:
Code Review Summary:
Correctness: ✓ PASS
- Logic correctly filters and sums even numbers
- Edge cases handled properly
Performance: ✓ GOOD
- Efficient O(n) algorithm
- Appropriate use of filter/reduce
Maintainability: ✓ EXCELLENT
- Clear function name and documentation
- Simple, readable implementation
Testing: ✓ COMPREHENSIVE
- All edge cases covered
- Good test descriptions
- Performance test included
Suggestions:
- Consider adding JSDoc examples
- Could extract even number check to a helper function for reusability
Overall: APPROVED - High quality implementation
Store this pattern in memory with key "patterns:sum-even-numbers"
For critical code, use the adversarial review loop:
Start an adversarial review loop for the sumEvenNumbers function
This calls review_loop_start:
{
"tool": "review_loop_start",
"arguments": {
"code": "export function sumEvenNumbers(numbers: number[]): number { ... }",
"maxIterations": 3
}
}The adversarial agent will:
- Try to break the code
- Find edge cases
- Identify security issues
- Demand fixes
If issues are found:
- Coder agent fixes the code
- Adversarial agent reviews again
- Loop continues until approved or max iterations
1. Spawn researcher agent
2. Research best practices for the task
3. Spawn coder agent
4. Implement based on research
5. Spawn tester agent
6. Create tests
1. Spawn architect agent
2. Design the solution
3. Spawn coder agent
4. Implement the design
5. Spawn reviewer agent
6. Review implementation
1. Spawn coder agent
2. Implement feature
3. Start adversarial review loop
4. Fix issues until approved
✓ GOOD: "user-auth-coder", "api-tester", "security-reviewer"
✗ BAD: "agent1", "test", "temp"
Use descriptive names that indicate:
- Purpose (coder, tester, reviewer)
- Context (user-auth, api, security)
✓ GOOD:
namespace: "user-auth"
key: "pattern:jwt-validation"
✗ BAD:
namespace: "default"
key: "stuff"
Use structured namespaces and keys:
- Namespace: Feature or module
- Key: Pattern or concept
✓ GOOD: Start session for each feature/task
✗ BAD: One session for everything
Sessions provide:
- Context isolation
- Resource cleanup
- Progress tracking
✓ GOOD: Break into specific, focused tasks
✗ BAD: One agent does everything
Example:
Task: Build authentication system
Decomposition:
1. Architect: Design auth flow
2. Coder: Implement JWT generation
3. Tester: Test JWT validation
4. Security Auditor: Security review
5. Documentation: API docs
Problem: Agent spawned but doesn't execute tasks
Solution:
- Check agent status:
agent_status - Verify provider configuration
- Check API key validity
- Review logs for errors
Problem: Stored data not retrievable
Solution:
- Verify namespace matches
- Check key spelling
- Use
memory_listto see all entries - Try FTS search instead of exact key
Problem: Agents can't access session data
Solution:
- Verify session is active:
session_status - Ensure agents spawned with correct sessionId
- Check session hasn't ended
- Understanding Agents - Deep dive into agent types
- Memory System - Advanced memory features
- Task Coordination - Multi-agent orchestration
- Code Review Workflow - Complete review process
- Multi-Agent Collaboration - Coordinate agents
- Adversarial Testing - Break your code
- Agent Tools - All agent management tools
- Memory Tools - Memory operations
- Session Tools - Session management
Related:
Getting Started
Core Concepts
Agent Guides
- Overview
- Coder
- Researcher
- Tester
- Reviewer
- Adversarial
- Architect
- Coordinator
- Analyst
- DevOps
- Documentation
- Security Auditor
MCP Tools
- Overview
- Agent Tools
- Memory Tools
- Task Tools
- Session Tools
- System Tools
- GitHub Tools
- Review Loop Tools
- Identity Tools
Recipes
- Index
- Code Review
- Doc Sync
- Multi-Agent
- Adversarial Testing
- Full-Stack Feature
- Memory Patterns
- GitHub Integration
Advanced
- Plugin Development
- Custom Agent Types
- Workflow Engine
- Vector Search Setup
- Web Dashboard
- Programmatic API
- Resource Monitoring
Reference