This file contains guidelines and commands for agentic coding tools working in this repository.
Revolution is a Node.js CLI tool that provides AI-powered capabilities through three main agents:
- ChatAgent: Conversational AI with credit tracking and logging
- ToolsAgent: Agentic tools mode (web search, scraping, computer use, MCP)
- CodingAgent: Agentic coding mode for app design and creation
The project uses ES modules ("type": "module"), LangChain for LLM integration, and GLM as the default model.
# Run all tests
npm test
# Start the CLI application
npm start
# Run the CLI directly
node ./bin/cli.js# Run a specific test file
node --test tests/crewEngine.test.js
# Run tests with pattern matching
node --test --test-name-pattern "CrewEngine"# Install dependencies
npm install
# Run in development mode
npm start
# Test specific functionality
node ./bin/cli.js chat
node ./bin/cli.js tools "search for something"
node ./bin/cli.js code "create a todo app"- ES Modules only: Use
import/exportsyntax - File extensions: Always use
.jsextensions in imports - Default exports: Use named exports for better tree-shaking
// ✅ Good
import { ChatAgent } from "./agents/chatAgent.js";
export { ChatAgent };
// ❌ Bad
const ChatAgent = require("./chatAgent");
module.exports = ChatAgent;- Node.js built-in modules
- Third-party dependencies
- Local modules (relative imports)
import { promises as fs } from "fs";
import path from "path";
import { Command } from "commander";
import chalk from "chalk";
import { createLLM } from "./config/llm.js";
import { ChatAgent } from "./agents/chatAgent.js";- Classes: PascalCase (
ChatAgent,CrewEngine) - Functions/Variables: camelCase (
createLLM,creditManager) - Constants: UPPER_SNAKE_CASE (
MAX_CONCURRENT_REQUESTS,DEFAULT_MODEL) - Files: camelCase with
.jsextension (chatAgent.js,crewEngine.js)
- Use async/await consistently
- Wrap async operations in try/catch blocks
- Provide meaningful error messages
// ✅ Good
async function generateFile(spec, filePath) {
try {
const code = await this.llm.invoke(messages);
await fs.writeFile(filePath, code, "utf8");
return filePath;
} catch (error) {
throw new Error(`Failed to generate file ${filePath}: ${error.message}`);
}
}
// ❌ Bad
function generateFile(spec, filePath) {
return this.llm.invoke(messages).then(code => {
return fs.writeFile(filePath, code, "utf8");
});
}- Use ES class syntax
- Constructor for dependency injection
- Private methods prefixed with underscore
- Export classes separately from instances
export class ChatAgent {
constructor(creditManager) {
this.llm = createLLM();
this.credits = creditManager;
this.histories = new Map();
}
_getHistory(userId) {
return this.histories.get(userId) || [];
}
async chatOnce(userId, userMessage, options = {}) {
// Implementation
}
}- Environment variables through
.envfile - Centralized configuration in
src/config/ - Default values with env override capability
// src/config/llm.js
const DEFAULT_MODEL = "GLM-4.5-Flash";
const DEFAULT_API_BASE = process.env.GLM_API_BASE || "https://api.z.ai/api/paas/v4/";- Use structured logging with context
- Separate loggers by domain
- Include relevant metadata
// src/config/logging.js
export const chatLogger = {
info: (...args) => console.log("[CHAT]", ...args),
};
// Usage
chatLogger.info(`user=${userId}`, { inputTokens, outputTokens, usage });- Use the factory pattern for LLM creation
- Implement rate limiting and credit tracking
- Support both streaming and non-streaming responses
import { createLLM } from "../config/llm.js";
export class ChatAgent {
constructor(creditManager) {
this.llm = createLLM({
temperature: 0.6,
creditManager,
userId: "cli-user"
});
}
}- Use
fs.promisesfor async file operations - Create directories recursively when needed
- Handle file paths with
pathmodule
import { promises as fs } from "fs";
import { dirname } from "path";
await fs.mkdir(dirname(filePath), { recursive: true });
await fs.writeFile(filePath, content, "utf8");- Use Commander.js for CLI framework
- Organize commands by functionality
- Provide clear help text and descriptions
program
.command("chat")
.description("Start a chat with AI (with credits & logs)")
.action(async () => {
// Implementation
});- Use Node.js built-in test runner (
node:test) - Place tests in
tests/directory - Name test files with
.test.jssuffix
- Use descriptive test names
- Mock external dependencies (LLM, file system)
- Test both success and error cases
import { test } from "node:test";
import assert from "node:assert";
test("ChatAgent should record usage after chat", async () => {
const fakeCredits = { recordUsage: () => {} };
const agent = new ChatAgent(fakeCredits);
// Test implementation
});Revolution includes a JavaScript-based workflow framework called "Gang" that replaces the previous YAML-based Crew system. The Gang framework allows you to orchestrate multiple AI members (agents) working together in structured workflows.
- Members: Individual AI agents with specific roles and tools
- Squads: Groups of members that can work in parallel or sequentially
- Workflows: Directed graphs defining execution flow between members and squads
- Memory: Shared conversation history for context retention
Using Factory Functions:
import { createGang, createMember, createWorkflow, createSquad } from "./src/workflows/gangEngine.js";
const researchGang = createGang({
name: "research-gang",
version: 1,
llm: { model: "GLM-4.5-Flash", temperature: 0.4 },
members: [
createMember("researcher", "Find and analyze information", ["web_search", "scrape_url"]),
createMember("writer", "Synthesize research into clear output", [])
],
workflow: createWorkflow("researcher", [
{ from: "researcher", to: "writer", when: "data_found" }
]),
observability: { enabled: true }
});Direct JavaScript Configuration:
export const gangConfig = {
name: "my-gang",
version: 1,
llm: {
model: "GLM-4.5-Flash",
temperature: 0.3
},
members: [
{
name: "analyst",
role: "Data analysis specialist",
tools: ["read_file", "list_directory"],
memoryId: "shared"
},
{
name: "reporter",
role: "Report generation specialist",
tools: [],
memoryId: "shared"
}
],
squads: [
{
name: "analysis-squad",
mode: "parallel",
members: ["analyst", "reporter"]
}
],
workflow: {
entry: "analyst",
steps: [
{ from: "analyst", to: "reporter", when: "analysis_complete" }
]
},
observability: {
enabled: true,
logLevel: "info",
markdownReport: { enabled: true }
},
tests: [
{
name: "basic-analysis",
input: "Analyze the data file",
asserts: [
{
type: "contains",
target: "analyst",
value: "data"
}
]
}
]
};From CLI:
# Using predefined gang template
node ./bin/cli.js gang research --input "Research latest AI trends"
# Using JavaScript configuration file
node ./bin/cli.js gang ./my-gang-config.js --input "Analyze project data"
# Run gang tests
node ./bin/cli.js gang ./my-gang-config.js --testsProgrammatically:
import { GangEngine } from "./src/workflows/gangEngine.js";
const engine = new GangEngine({ config: gangConfig });
const result = await engine.runOnce("Research Node.js best practices");
// Run tests
const testResults = await engine.runTests();- research: Research and content synthesis team
- analysis: Data analysis and reporting team
Define tests in your gang configuration:
tests: [
{
name: "research-completes",
input: "Find information about quantum computing",
asserts: [
{
type: "contains",
target: "researcher",
value: "quantum"
},
{
type: "contains",
target: "writer",
value: "research"
}
]
}
]Test reports are generated in gang_reports/ directory in both JSON and Markdown formats.
GLM_API_KEY=your_api_key_here
GLM_API_BASE=https://api.z.ai/api/paas/v4/
LLM_MAX_CONCURRENCY=1- Node.js (ES modules support required)
- GLM API access
- No external build tools needed
- Maintain conversation history per user
- Track token usage and credits
- Support streaming responses
- Log interactions for observability
- Integrate with external APIs (web search, scraping)
- Handle MCP (Model Context Protocol) if configured
- Provide tool descriptions and usage
- Timeout long-running operations
- Generate production-quality code
- Support both new file creation and editing
- Provide design reasoning before code generation
- Handle file system operations safely
- Never log API keys or sensitive data
- Validate file paths to prevent directory traversal
- Sanitize user inputs before processing
- Use environment variables for configuration