feat(templates): centralize workspace templates

This commit is contained in:
Peter Steinberger
2025-12-19 18:12:01 +00:00
parent 6cbfa01176
commit 590f3d0e8f
8 changed files with 247 additions and 22 deletions

View File

@@ -1,6 +1,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { resolveUserPath } from "../utils.js";
@@ -9,21 +10,35 @@ export const DEFAULT_AGENTS_FILENAME = "AGENTS.md";
export const DEFAULT_SOUL_FILENAME = "SOUL.md";
export const DEFAULT_TOOLS_FILENAME = "TOOLS.md";
const DEFAULT_AGENTS_TEMPLATE = `# AGENTS.md Clawdis Workspace
const DEFAULT_AGENTS_TEMPLATE = `# AGENTS.md - Clawdis Workspace
This folder is the assistants working directory.
This folder is the assistant's working directory.
## Backup tip (recommended)
If you treat this workspace as the agent's "memory", make it a git repo (ideally private) so identity
and notes are backed up.
\`\`\`bash
git init
git add AGENTS.md
git commit -m "Add agent workspace"
\`\`\`
## Safety defaults
- Dont exfiltrate secrets or private data.
- Dont run destructive commands unless explicitly asked.
- Don't exfiltrate secrets or private data.
- Don't run destructive commands unless explicitly asked.
- Be concise in chat; write longer output to files in this workspace.
## How to use this
- Put project notes, scratch files, and “memory” here.
- Customize this file with additional instructions for your assistant.
## Daily memory (recommended)
- Keep a short daily log at memory/YYYY-MM-DD.md (create memory/ if needed).
- On session start, read today + yesterday if present.
- Capture durable facts, preferences, and decisions; avoid secrets.
## Customize
- Add your preferred style, rules, and "memory" here.
`;
const DEFAULT_SOUL_TEMPLATE = `# SOUL.md Persona & Boundaries
const DEFAULT_SOUL_TEMPLATE = `# SOUL.md - Persona & Boundaries
Describe who the assistant is, tone, and boundaries.
@@ -32,7 +47,7 @@ Describe who the assistant is, tone, and boundaries.
- Never send streaming/partial replies to external messaging surfaces.
`;
const DEFAULT_TOOLS_TEMPLATE = `# TOOLS.md User Tool Notes (editable)
const DEFAULT_TOOLS_TEMPLATE = `# TOOLS.md - User Tool Notes (editable)
This file is for *your* notes about external tools and conventions.
It does not define which tools exist; Clawdis provides built-in tools internally.
@@ -49,6 +64,34 @@ It does not define which tools exist; Clawdis provides built-in tools internally
Add whatever else you want the assistant to know about your local toolchain.
`;
const TEMPLATE_DIR = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"../../docs/templates",
);
function stripFrontMatter(content: string): string {
if (!content.startsWith("---")) return content;
const endIndex = content.indexOf("\n---", 3);
if (endIndex === -1) return content;
const start = endIndex + "\n---".length;
let trimmed = content.slice(start);
trimmed = trimmed.replace(/^\s+/, "");
return trimmed;
}
async function loadTemplate(
name: string,
fallback: string,
): Promise<string> {
const templatePath = path.join(TEMPLATE_DIR, name);
try {
const content = await fs.readFile(templatePath, "utf-8");
return stripFrontMatter(content);
} catch {
return fallback;
}
}
export type WorkspaceBootstrapFileName =
| typeof DEFAULT_AGENTS_FILENAME
| typeof DEFAULT_SOUL_FILENAME
@@ -94,9 +137,22 @@ export async function ensureAgentWorkspace(params?: {
const soulPath = path.join(dir, DEFAULT_SOUL_FILENAME);
const toolsPath = path.join(dir, DEFAULT_TOOLS_FILENAME);
await writeFileIfMissing(agentsPath, DEFAULT_AGENTS_TEMPLATE);
await writeFileIfMissing(soulPath, DEFAULT_SOUL_TEMPLATE);
await writeFileIfMissing(toolsPath, DEFAULT_TOOLS_TEMPLATE);
const agentsTemplate = await loadTemplate(
DEFAULT_AGENTS_FILENAME,
DEFAULT_AGENTS_TEMPLATE,
);
const soulTemplate = await loadTemplate(
DEFAULT_SOUL_FILENAME,
DEFAULT_SOUL_TEMPLATE,
);
const toolsTemplate = await loadTemplate(
DEFAULT_TOOLS_FILENAME,
DEFAULT_TOOLS_TEMPLATE,
);
await writeFileIfMissing(agentsPath, agentsTemplate);
await writeFileIfMissing(soulPath, soulTemplate);
await writeFileIfMissing(toolsPath, toolsTemplate);
return { dir, agentsPath, soulPath, toolsPath };
}