feat: enhance workspace scaffolding with new identity and soul templates, and support for default user file
This commit is contained in:
@@ -66,7 +66,8 @@ export async function runSetup(opts: SetupOpts): Promise<SetupResult> {
|
|||||||
|
|
||||||
await writePluginConfig(opts.api, agentId, opts.projectExecution);
|
await writePluginConfig(opts.api, agentId, opts.projectExecution);
|
||||||
|
|
||||||
const filesWritten = await scaffoldWorkspace(workspacePath);
|
const defaultWorkspacePath = getDefaultWorkspacePath(opts.api);
|
||||||
|
const filesWritten = await scaffoldWorkspace(workspacePath, defaultWorkspacePath);
|
||||||
|
|
||||||
const models = buildModelConfig(opts.models);
|
const models = buildModelConfig(opts.models);
|
||||||
await writeModelsToWorkflow(workspacePath, models);
|
await writeModelsToWorkflow(workspacePath, models);
|
||||||
@@ -140,6 +141,15 @@ function buildModelConfig(overrides?: SetupOpts["models"]): ModelConfig {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDefaultWorkspacePath(api: OpenClawPluginApi): string | undefined {
|
||||||
|
try {
|
||||||
|
const config = api.runtime.config.loadConfig();
|
||||||
|
return (config as any).agents?.defaults?.workspace ?? undefined;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write model configuration to workflow.yaml (single source of truth).
|
* Write model configuration to workflow.yaml (single source of truth).
|
||||||
* Reads the existing workflow.yaml, merges model overrides into the roles section, and writes back.
|
* Reads the existing workflow.yaml, merges model overrides into the roles section, and writes back.
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import path from "node:path";
|
|||||||
import {
|
import {
|
||||||
AGENTS_MD_TEMPLATE,
|
AGENTS_MD_TEMPLATE,
|
||||||
HEARTBEAT_MD_TEMPLATE,
|
HEARTBEAT_MD_TEMPLATE,
|
||||||
|
IDENTITY_MD_TEMPLATE,
|
||||||
|
SOUL_MD_TEMPLATE,
|
||||||
WORKFLOW_YAML_TEMPLATE,
|
WORKFLOW_YAML_TEMPLATE,
|
||||||
DEFAULT_ROLE_INSTRUCTIONS,
|
DEFAULT_ROLE_INSTRUCTIONS,
|
||||||
} from "../templates.js";
|
} from "../templates.js";
|
||||||
@@ -57,21 +59,51 @@ export async function ensureDefaultFiles(workspacePath: string): Promise<void> {
|
|||||||
/**
|
/**
|
||||||
* Write all workspace files for a DevClaw agent.
|
* Write all workspace files for a DevClaw agent.
|
||||||
* Returns the list of files that were written (skips files that already exist).
|
* Returns the list of files that were written (skips files that already exist).
|
||||||
|
*
|
||||||
|
* @param defaultWorkspacePath — If provided, USER.md is copied from here (only if not already present).
|
||||||
*/
|
*/
|
||||||
export async function scaffoldWorkspace(workspacePath: string): Promise<string[]> {
|
export async function scaffoldWorkspace(workspacePath: string, defaultWorkspacePath?: string): Promise<string[]> {
|
||||||
// Migrate old layout if detected
|
// Migrate old layout if detected
|
||||||
await migrateWorkspaceLayout(workspacePath);
|
await migrateWorkspaceLayout(workspacePath);
|
||||||
|
|
||||||
|
const written: string[] = [];
|
||||||
|
|
||||||
// AGENTS.md (backup existing — stays at workspace root)
|
// AGENTS.md (backup existing — stays at workspace root)
|
||||||
await backupAndWrite(path.join(workspacePath, "AGENTS.md"), AGENTS_MD_TEMPLATE);
|
await backupAndWrite(path.join(workspacePath, "AGENTS.md"), AGENTS_MD_TEMPLATE);
|
||||||
|
written.push("AGENTS.md");
|
||||||
|
|
||||||
// HEARTBEAT.md (stays at workspace root)
|
// HEARTBEAT.md (stays at workspace root)
|
||||||
await backupAndWrite(path.join(workspacePath, "HEARTBEAT.md"), HEARTBEAT_MD_TEMPLATE);
|
await backupAndWrite(path.join(workspacePath, "HEARTBEAT.md"), HEARTBEAT_MD_TEMPLATE);
|
||||||
|
written.push("HEARTBEAT.md");
|
||||||
|
|
||||||
|
// IDENTITY.md (create-only — never overwrite user customizations)
|
||||||
|
const identityPath = path.join(workspacePath, "IDENTITY.md");
|
||||||
|
if (!await fileExists(identityPath)) {
|
||||||
|
await fs.writeFile(identityPath, IDENTITY_MD_TEMPLATE, "utf-8");
|
||||||
|
written.push("IDENTITY.md");
|
||||||
|
}
|
||||||
|
|
||||||
|
// SOUL.md (create-only — never overwrite user customizations)
|
||||||
|
const soulPath = path.join(workspacePath, "SOUL.md");
|
||||||
|
if (!await fileExists(soulPath)) {
|
||||||
|
await fs.writeFile(soulPath, SOUL_MD_TEMPLATE, "utf-8");
|
||||||
|
written.push("SOUL.md");
|
||||||
|
}
|
||||||
|
|
||||||
|
// USER.md — copy from default workspace if available (create-only)
|
||||||
|
const userPath = path.join(workspacePath, "USER.md");
|
||||||
|
if (!await fileExists(userPath) && defaultWorkspacePath) {
|
||||||
|
const sourceUser = path.join(defaultWorkspacePath, "USER.md");
|
||||||
|
if (await fileExists(sourceUser)) {
|
||||||
|
await fs.copyFile(sourceUser, userPath);
|
||||||
|
written.push("USER.md");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure all data-dir defaults (workflow.yaml, prompts, etc.)
|
// Ensure all data-dir defaults (workflow.yaml, prompts, etc.)
|
||||||
await ensureDefaultFiles(workspacePath);
|
await ensureDefaultFiles(workspacePath);
|
||||||
|
|
||||||
return ["AGENTS.md", "HEARTBEAT.md"];
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -226,6 +226,10 @@ All orchestration goes through these tools. You do NOT manually manage sessions,
|
|||||||
| \`work_finish\` | End-to-end: label transition, state update, issue close/reopen |
|
| \`work_finish\` | End-to-end: label transition, state update, issue close/reopen |
|
||||||
| \`design_task\` | Spawn an architect for design investigation. Creates To Design issue and dispatches architect |
|
| \`design_task\` | Spawn an architect for design investigation. Creates To Design issue and dispatches architect |
|
||||||
|
|
||||||
|
### First Thing on Session Start
|
||||||
|
|
||||||
|
**Always call \`status\` first** when you start a new session. This tells you which projects you manage, what's in the queue, and which workers are active. Don't guess — check.
|
||||||
|
|
||||||
### Pipeline Flow
|
### Pipeline Flow
|
||||||
|
|
||||||
\`\`\`
|
\`\`\`
|
||||||
@@ -295,6 +299,56 @@ export const HEARTBEAT_MD_TEMPLATE = `# HEARTBEAT.md
|
|||||||
Do nothing. An internal token-free heartbeat service handles health checks and queue dispatch automatically.
|
Do nothing. An internal token-free heartbeat service handles health checks and queue dispatch automatically.
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const IDENTITY_MD_TEMPLATE = `# IDENTITY.md - Who Am I?
|
||||||
|
|
||||||
|
- **Name:** DevClaw
|
||||||
|
- **Creature:** Development orchestrator — plans, dispatches, never codes
|
||||||
|
- **Vibe:** Direct, decisive, transparent. No fluff.
|
||||||
|
- **Emoji:** 🦞
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SOUL_MD_TEMPLATE = `# SOUL.md - DevClaw Orchestrator Identity
|
||||||
|
|
||||||
|
You are a **development orchestrator** — you plan, prioritize, and dispatch. You never write code yourself.
|
||||||
|
|
||||||
|
## Core Principles
|
||||||
|
|
||||||
|
**Be direct.** Skip pleasantries, get to the point. Say what you're doing and why.
|
||||||
|
|
||||||
|
**Be decisive.** Evaluate task complexity, pick the right level, dispatch. Don't deliberate when the answer is obvious.
|
||||||
|
|
||||||
|
**Be transparent.** Always include issue URLs. Always explain what happened and what's next. No black boxes.
|
||||||
|
|
||||||
|
**Be resourceful.** Check status before asking. Read the issue before dispatching. Understand the codebase before planning. Come back with answers, not questions.
|
||||||
|
|
||||||
|
## How You Work
|
||||||
|
|
||||||
|
- You receive requests via chat (Telegram, WhatsApp, or web)
|
||||||
|
- You break work into issues, assign complexity levels, and dispatch workers
|
||||||
|
- Workers (developer, tester, architect) do the actual work in isolated sessions
|
||||||
|
- You track progress, handle failures, and keep the human informed
|
||||||
|
- The heartbeat runs automatically — you don't manage it
|
||||||
|
|
||||||
|
## Communication Style
|
||||||
|
|
||||||
|
- Concise status updates with issue links
|
||||||
|
- Use the announcement format from tool responses
|
||||||
|
- Flag blockers and failures immediately
|
||||||
|
- Don't over-explain routine operations
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- **Never write code** — dispatch a developer worker
|
||||||
|
- **Never skip testing** — every code change goes through QA
|
||||||
|
- **Never close issues** without a tester pass
|
||||||
|
- **Ask before** architectural decisions affecting multiple projects
|
||||||
|
|
||||||
|
## Continuity
|
||||||
|
|
||||||
|
Each session starts fresh. AGENTS.md defines your operational procedures. This file defines who you are. USER.md tells you about the humans you work with. Update these files as you learn.
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate WORKFLOW_YAML_TEMPLATE from the runtime objects (single source of truth).
|
* Generate WORKFLOW_YAML_TEMPLATE from the runtime objects (single source of truth).
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user