diff --git a/apps/cli/src/commands/create.ts b/apps/cli/src/commands/create.ts new file mode 100644 index 0000000..4a6125c --- /dev/null +++ b/apps/cli/src/commands/create.ts @@ -0,0 +1,39 @@ +/** + * `claudemesh create` — Create a new mesh with an optional template. + * Lists available templates if --list-templates is passed. + */ +import { listTemplates, getTemplate } from "../templates/index.js"; + +export function runCreate(args: Record): void { + if (args["list-templates"]) { + console.log("Available mesh templates:\n"); + for (const t of listTemplates()) { + console.log(` ${t.name}`); + console.log(` ${t.description}`); + console.log(` Groups: ${t.groups.map((g) => g.name).join(", ") || "(none)"}`); + console.log(` State keys: ${Object.keys(t.stateKeys).join(", ") || "(none)"}`); + console.log(); + } + return; + } + + const templateName = args.template as string | undefined; + if (templateName) { + const template = getTemplate(templateName); + if (!template) { + console.error(`Unknown template "${templateName}". Use --list-templates to see available options.`); + process.exit(1); + } + console.log(`Template "${template.name}" loaded:`); + console.log(` Groups: ${template.groups.map((g) => `@${g.name}`).join(", ")}`); + console.log(` State keys: ${Object.keys(template.stateKeys).join(", ")}`); + console.log(` Hint: ${template.systemPromptHint.slice(0, 80)}...`); + console.log(); + console.log("Template applied. Use `claudemesh launch` with --groups to join the predefined groups."); + // Future: wire into actual mesh creation API + return; + } + + console.log("Usage: claudemesh create --template "); + console.log(" claudemesh create --list-templates"); +} diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index d799f71..436ea1c 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -28,6 +28,7 @@ import { runStateGet, runStateSet, runStateList } from "./commands/state"; import { runRemember, runRecall } from "./commands/memory"; import { runInfo } from "./commands/info"; import { runRemind } from "./commands/remind"; +import { runCreate } from "./commands/create"; import { VERSION } from "./version"; const launch = defineCommand({ @@ -141,6 +142,14 @@ const main = defineCommand({ }, subCommands: { launch, + create: defineCommand({ + meta: { name: "create", description: "Create a new mesh from a template" }, + args: { + template: { type: "string", description: "Template name (dev-team, research, ops-incident, simulation, personal)" }, + "list-templates": { type: "boolean", description: "List available templates", default: false }, + }, + run({ args }) { runCreate(args); }, + }), install, uninstall: defineCommand({ meta: { name: "uninstall", description: "Remove MCP server and hooks" }, diff --git a/apps/cli/src/templates/dev-team.json b/apps/cli/src/templates/dev-team.json new file mode 100644 index 0000000..b6fbf0f --- /dev/null +++ b/apps/cli/src/templates/dev-team.json @@ -0,0 +1,17 @@ +{ + "name": "dev-team", + "description": "Software development team with frontend, backend, and devops groups", + "groups": [ + { "name": "frontend", "roles": ["lead", "member"] }, + { "name": "backend", "roles": ["lead", "member"] }, + { "name": "devops", "roles": ["lead", "member"] }, + { "name": "qa", "roles": ["lead", "member"] } + ], + "stateKeys": { + "sprint": "current", + "deploy-frozen": "false", + "pr-queue": "[]" + }, + "suggestedRoles": ["lead", "member", "reviewer"], + "systemPromptHint": "You are part of a dev team. Coordinate with @frontend, @backend, @devops groups. Check state keys for sprint status and deploy freezes before making changes." +} diff --git a/apps/cli/src/templates/index.ts b/apps/cli/src/templates/index.ts new file mode 100644 index 0000000..e71ed59 --- /dev/null +++ b/apps/cli/src/templates/index.ts @@ -0,0 +1,30 @@ +import devTeam from "./dev-team.json" with { type: "json" }; +import research from "./research.json" with { type: "json" }; +import opsIncident from "./ops-incident.json" with { type: "json" }; +import simulation from "./simulation.json" with { type: "json" }; +import personal from "./personal.json" with { type: "json" }; + +export interface MeshTemplate { + name: string; + description: string; + groups: Array<{ name: string; roles: string[] }>; + stateKeys: Record; + suggestedRoles: string[]; + systemPromptHint: string; +} + +export const TEMPLATES: Record = { + "dev-team": devTeam, + research, + "ops-incident": opsIncident, + simulation, + personal, +}; + +export function listTemplates(): MeshTemplate[] { + return Object.values(TEMPLATES); +} + +export function getTemplate(name: string): MeshTemplate | undefined { + return TEMPLATES[name]; +} diff --git a/apps/cli/src/templates/ops-incident.json b/apps/cli/src/templates/ops-incident.json new file mode 100644 index 0000000..da5a779 --- /dev/null +++ b/apps/cli/src/templates/ops-incident.json @@ -0,0 +1,17 @@ +{ + "name": "ops-incident", + "description": "Incident response team with oncall, comms, and engineering groups", + "groups": [ + { "name": "oncall", "roles": ["primary", "secondary"] }, + { "name": "comms", "roles": ["lead", "scribe"] }, + { "name": "engineering", "roles": ["lead", "responder"] } + ], + "stateKeys": { + "incident-status": "investigating", + "severity": "unknown", + "commander": "", + "timeline": "[]" + }, + "suggestedRoles": ["commander", "primary-oncall", "scribe", "responder"], + "systemPromptHint": "INCIDENT MODE. Priority: now for all messages. Update incident-status state. Commander coordinates. Scribe maintains timeline. Engineering fixes." +} diff --git a/apps/cli/src/templates/personal.json b/apps/cli/src/templates/personal.json new file mode 100644 index 0000000..41a3603 --- /dev/null +++ b/apps/cli/src/templates/personal.json @@ -0,0 +1,11 @@ +{ + "name": "personal", + "description": "Private mesh for a single user — all sessions auto-join", + "groups": [], + "stateKeys": { + "focus": "", + "todos": "[]" + }, + "suggestedRoles": [], + "systemPromptHint": "Personal workspace. All your Claude Code sessions share this mesh. Use state keys to track focus and todos across sessions." +} diff --git a/apps/cli/src/templates/research.json b/apps/cli/src/templates/research.json new file mode 100644 index 0000000..7e53d72 --- /dev/null +++ b/apps/cli/src/templates/research.json @@ -0,0 +1,16 @@ +{ + "name": "research", + "description": "Research and analysis team focused on deep investigation and knowledge sharing", + "groups": [ + { "name": "analysis", "roles": ["lead", "analyst"] }, + { "name": "writing", "roles": ["lead", "writer", "reviewer"] }, + { "name": "data", "roles": ["engineer", "analyst"] } + ], + "stateKeys": { + "research-topic": "", + "phase": "exploration", + "findings-count": "0" + }, + "suggestedRoles": ["lead", "analyst", "writer", "reviewer"], + "systemPromptHint": "You are part of a research team. Share findings via remember(), use recall() before starting new analysis. Coordinate phases through state keys." +} diff --git a/apps/cli/src/templates/simulation.json b/apps/cli/src/templates/simulation.json new file mode 100644 index 0000000..4c2118c --- /dev/null +++ b/apps/cli/src/templates/simulation.json @@ -0,0 +1,17 @@ +{ + "name": "simulation", + "description": "Load testing simulation with configurable time multiplier and user personas", + "groups": [ + { "name": "personas", "roles": ["admin", "user", "customer"] }, + { "name": "observers", "roles": ["monitor", "analyst"] }, + { "name": "control", "roles": ["orchestrator"] } + ], + "stateKeys": { + "clock-speed": "x1", + "sim-status": "paused", + "tick-count": "0", + "scenario": "" + }, + "suggestedRoles": ["orchestrator", "persona", "monitor"], + "systemPromptHint": "SIMULATION MODE. Follow the clock-speed state for time multiplier. Act according to your persona role and the simulated time. Report actions to @observers." +}