openclaw-agent-builder 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.html CHANGED
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>OpenClaw Agent Builder</title>
7
- <script type="module" crossorigin src="/assets/index-CHYw1YB7.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-Dc_24nLn.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-C9IXUW-V.css">
9
9
  </head>
10
10
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-agent-builder",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Wizard to create and deploy OpenClaw agents and multi-agent teams — runs as a desktop app or via npx",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Generate AGENTS.md for an agent.
3
3
  * Pure function — never invents content not in the TeamSpec.
4
+ * Aligned with OpenClaw upstream template.
4
5
  */
5
6
  export function generateAgents(agent, teamSpec) {
6
7
  const neverRules = agent.never && agent.never.length > 0
@@ -55,7 +56,7 @@ Escalate to **${teamSpec.orchestration.router_agent}** for coordination decision
55
56
  |----------|------|---------|
56
57
  ${rows}
57
58
  `;
58
- } else {
59
+ } else if (otherAgents.length > 0) {
59
60
  handoffSection = `
60
61
  ## Cross-Agent Handoffs
61
62
 
@@ -63,14 +64,48 @@ ${rows}
63
64
  `;
64
65
  }
65
66
 
66
- return `# AGENTS.md - Operating Rules
67
+ // Group chat section for multi-agent teams
68
+ let groupChatSection = '';
69
+ if (otherAgents.length > 0) {
70
+ groupChatSection = `
71
+ ## Group Chat Rules
72
+
73
+ - Respond selectively — only when mentioned or when you can add genuine value.
74
+ - Don't repeat what another agent just said.
75
+ - If a task isn't yours, let the right agent handle it.
76
+ `;
77
+ }
78
+
79
+ // Safety boundaries section
80
+ const safetySection = `
81
+ ## Safety Boundaries
82
+
83
+ **Safe actions (no permission needed):**
84
+ - Reading files in your workspace
85
+ - Web searches and lookups
86
+ - Internal organization and memory updates
87
+
88
+ **Needs permission:**
89
+ - Sending emails or public posts
90
+ - Leaving your workspace directory
91
+ - Actions that affect external systems
92
+ `;
93
+
94
+ return `# AGENTS.md — Operating Rules
67
95
 
68
96
  ## Session Startup
69
97
 
70
98
  1. Read \`SOUL.md\` — who you are
71
99
  2. Read \`USER.md\` — who you're helping
72
- 3. Read \`MEMORY.md\` — your long-term memory
100
+ 3. Read \`MEMORY.md\` — your curated long-term memory
73
101
  4. Read \`memory/YYYY-MM-DD.md\` (today + yesterday) for recent context
102
+ 5. Check your task queue
103
+
104
+ ## Memory Architecture
105
+
106
+ - **Daily logs:** \`memory/YYYY-MM-DD.md\` — write today's context here
107
+ - **Curated memory:** \`MEMORY.md\` — the distilled version, updated periodically
108
+ - If you want to remember something, **write it to a file**
74
109
 
75
110
  ## Red Lines
76
111
 
@@ -83,5 +118,5 @@ ${agent.escalation || '// TODO: define escalation rules'}
83
118
  ## Failure Behavior
84
119
 
85
120
  ${agent.failure || '// TODO: define failure behavior'}
86
- ${orchestrationSection}${handoffSection}`;
121
+ ${safetySection}${orchestrationSection}${handoffSection}${groupChatSection}`;
87
122
  }
@@ -1,42 +1,36 @@
1
1
  /**
2
2
  * Generate BOOTSTRAP.md for an agent.
3
3
  * Pure function.
4
+ * Aligned with OpenClaw upstream template — a conversational first-run ritual.
4
5
  */
5
6
  export function generateBootstrap(agent, _teamSpec) {
6
- const inputsSection = agent.inputs
7
- ? agent.inputs
8
- .split(/[\n;]+/)
9
- .map(s => s.trim())
10
- .filter(Boolean)
11
- .map(s => `- ${s}`)
12
- .join('\n')
13
- : '- // TODO: inputs not specified';
7
+ return `# BOOTSTRAP.md — First Run
14
8
 
15
- return `# BOOTSTRAP.md - Session Startup
9
+ Hey. You're new here. Let's figure out who you are.
16
10
 
17
- ## Who You Are
11
+ We've already prepared your identity files, so start by reading them:
18
12
 
19
- **${agent.name}** ${agent.mission || '// TODO: mission not specified'}
13
+ 1. Read \`SOUL.md\` your identity and purpose
14
+ 2. Read \`IDENTITY.md\` — your name, vibe, and emoji
15
+ 3. Read \`USER.md\` — who you're helping
16
+ 4. Read \`MEMORY.md\` — long-term memory (probably empty)
20
17
 
21
- ## What Triggers You
18
+ ## The Four Things to Discover
22
19
 
23
- ${inputsSection}
20
+ - **Name:** You're **${agent.name}**. Does it fit?
21
+ - **Nature:** What kind of creature are you? AI assistant? Digital familiar? Something else?
22
+ - **Vibe:** How do you communicate? Formal? Casual? Terse? Playful?
23
+ - **Emoji:** Pick one that represents you.
24
24
 
25
- ## Startup Checklist
25
+ ## What to Do Next
26
26
 
27
- 1. Read \`SOUL.md\` your identity and values
28
- 2. Read \`USER.md\` who you're helping
29
- 3. Read \`MEMORY.md\` long-term memory
30
- 4. Read \`memory/YYYY-MM-DD.md\`recent context
31
- 5. Check your task queue
32
-
33
- ## First Run
34
-
35
- If this is your first session, introduce yourself and confirm your mission.
36
- Update \`IDENTITY.md\` and \`USER.md\` with what you learn.
27
+ - Talk to your human. Learn about them.
28
+ - Update \`IDENTITY.md\` with anything you discover about yourself.
29
+ - Update \`USER.md\` with what you learn about them.
30
+ - Start building your memory — write things down.
37
31
 
38
32
  ---
39
33
 
40
- _Delete this file once you're up and running. You won't need it again._
34
+ _Delete this file after your first run. You won't need it again._
41
35
  `;
42
36
  }
@@ -1,15 +1,17 @@
1
1
  /**
2
2
  * Generate IDENTITY.md for an agent.
3
3
  * Pure function.
4
+ * Aligned with OpenClaw upstream template.
4
5
  */
5
6
  export function generateIdentity(agent, _teamSpec) {
6
7
  const roleShort = agent.mission
7
8
  ? agent.mission.split('.')[0].slice(0, 80)
8
9
  : '// TODO';
9
10
 
10
- return `# IDENTITY.md - Who Am I?
11
+ return `# IDENTITY.md Who Am I?
11
12
 
12
13
  - **Name:** ${agent.name}
14
+ - **Creature:** // TODO (AI assistant? Digital familiar? Something else?)
13
15
  - **Role:** ${roleShort}
14
16
  - **Vibe:** // TODO
15
17
  - **Emoji:** // TODO
@@ -5,8 +5,6 @@ import { generateUser } from './user.js';
5
5
  import { generateTools } from './tools.js';
6
6
  import { generateBootstrap } from './bootstrap.js';
7
7
  import { generateMemory, generateMemoryReadme } from './memory.js';
8
- import { generateTeam } from './team.js';
9
- import { generateRouting } from './routing.js';
10
8
 
11
9
  function generateSkillsReadme(agent, teamSpec) {
12
10
  const recommended = teamSpec.capabilities?.recommendedSkills || [];
@@ -49,19 +47,7 @@ ${installLines}
49
47
  export function generateFiles(teamSpec) {
50
48
  const files = [];
51
49
 
52
- // 1. team/TEAM.md
53
- files.push({
54
- path: 'team/TEAM.md',
55
- content: generateTeam(teamSpec),
56
- });
57
-
58
- // 2. gateway/openclaw.routing.json5
59
- files.push({
60
- path: 'gateway/openclaw.routing.json5',
61
- content: generateRouting(teamSpec),
62
- });
63
-
64
- // 3. Per-agent files, alphabetically by agentId
50
+ // Per-agent files, alphabetically by agentId
65
51
  const sortedAgents = [...teamSpec.agents].sort((a, b) => a.id.localeCompare(b.id));
66
52
 
67
53
  for (const agent of sortedAgents) {
@@ -1,53 +1,54 @@
1
1
  /**
2
2
  * Generate SOUL.md for an agent.
3
3
  * Pure function — never invents content not in the TeamSpec.
4
+ * Aligned with OpenClaw upstream template.
4
5
  */
5
6
  export function generateSoul(agent, teamSpec) {
6
7
  const otherAgents = teamSpec.agents.filter(a => a.id !== agent.id);
7
8
 
8
- const whatIDo = agent.outputs
9
- ? agent.outputs
10
- .split(/[\n;]+/)
11
- .map(s => s.trim())
12
- .filter(Boolean)
13
- .map(s => `- ${s}`)
14
- .join('\n')
15
- : '- // TODO: outputs not specified';
16
-
17
9
  const teamSection = otherAgents.length > 0
18
10
  ? otherAgents.map(a => `- **${a.name}** — ${a.mission || '// TODO: mission'}`).join('\n')
19
11
  : teamSpec.team && teamSpec.team.name
20
12
  ? `- Working solo within **${teamSpec.team.name}**`
21
- : '- // TODO: team context';
13
+ : '';
22
14
 
23
15
  const neverRules = agent.never && agent.never.length > 0
24
16
  ? agent.never.map(r => `- **NEVER** ${r}`).join('\n')
25
- : '- // TODO: define never rules';
26
-
27
- return `# SOUL.md - Who I Am
28
-
29
- I'm **${agent.name}** — ${agent.mission || '// TODO: mission not specified'}
17
+ : '- // TODO: define hard rules';
30
18
 
31
- ## My Purpose
19
+ const behaviorGuidelines = `- Skip the "Great question!" — just help.
20
+ - Be bold internally, cautious externally.
21
+ - If unsure, say so. Don't hallucinate facts.
22
+ - ${agent.failure ? agent.failure : '// TODO: what to do when things go wrong'}
23
+ - ${agent.escalation ? `Escalation: ${agent.escalation}` : '// TODO: escalation rules'}`;
32
24
 
33
- ${agent.mission || '// TODO: describe agent purpose in detail'}
34
-
35
- ## What I Do
25
+ let teamBlock = '';
26
+ if (teamSection) {
27
+ teamBlock = `
28
+ ## My Team
36
29
 
37
- ${whatIDo}
30
+ ${teamSection}
31
+ `;
32
+ }
38
33
 
39
- ## How I Operate
34
+ return `# SOUL.md — Who I Am
40
35
 
41
- ${agent.failure ? `**Failure behavior:** ${agent.failure}` : '// TODO: failure behavior'}
36
+ I'm **${agent.name}** ${agent.mission || '// TODO: mission not specified'}
42
37
 
43
- ${agent.escalation ? `**Escalation:** ${agent.escalation}` : '// TODO: escalation rules'}
38
+ ## Purpose
44
39
 
45
- ## My Team
40
+ ${agent.mission || '// TODO: describe what you do and why it matters'}
46
41
 
47
- ${teamSection}
42
+ ## Behavioral Guidelines
48
43
 
44
+ ${behaviorGuidelines}
45
+ ${teamBlock}
49
46
  ## Hard Rules
50
47
 
51
48
  ${neverRules}
49
+
50
+ ---
51
+
52
+ _Update this file as you evolve. This is your north star._
52
53
  `;
53
54
  }
@@ -1,42 +1,37 @@
1
1
  /**
2
2
  * Generate TOOLS.md for an agent.
3
3
  * Pure function.
4
+ * Aligned with OpenClaw upstream template — this file is for local
5
+ * environment notes (device names, SSH hosts, speaker IDs), NOT
6
+ * agent inputs/outputs.
4
7
  */
5
8
  export function generateTools(agent, _teamSpec) {
6
- const inputsSection = agent.inputs
7
- ? agent.inputs
8
- .split(/[\n;]+/)
9
- .map(s => s.trim())
10
- .filter(Boolean)
11
- .map(s => `- ${s}`)
12
- .join('\n')
13
- : '- // TODO: inputs not specified';
9
+ return `# TOOLS.md — Local Environment Notes
14
10
 
15
- const outputsSection = agent.outputs
16
- ? agent.outputs
17
- .split(/[\n;]+/)
18
- .map(s => s.trim())
19
- .filter(Boolean)
20
- .map(s => `- ${s}`)
21
- .join('\n')
22
- : '- // TODO: outputs not specified';
11
+ Skills define how your tools work. This file is for **your specifics** — the names, addresses, and quirks of your local setup.
23
12
 
24
- return `# TOOLS.md - Local Notes
13
+ ## Device Names
25
14
 
26
- ## Inputs / Triggers
15
+ // TODO: List devices by friendly name
16
+ // Example: "Living Room TV" → 192.168.1.42
27
17
 
28
- ${inputsSection}
18
+ ## SSH Hosts
29
19
 
30
- ## Outputs
20
+ // TODO: List SSH hosts and their purposes
21
+ // Example: homelab → user@192.168.1.100
31
22
 
32
- ${outputsSection}
23
+ ## Speaker / Room Assignments
33
24
 
34
- ## Environment
25
+ // TODO: Map speakers or rooms to zones
26
+ // Example: "Office" → media_player.office_sonos
35
27
 
36
- // TODO: Add environment-specific details (API keys locations, SSH hosts, device names, etc.)
28
+ ## Voice Preferences
37
29
 
38
- ## Skills
30
+ // TODO: Note any voice/TTS preferences
31
+ // Example: Default voice: alloy, Speed: 1.0
39
32
 
40
- // TODO: List installed skills and their configurations
33
+ ## Other Environment Notes
34
+
35
+ // TODO: API key locations, local paths, service URLs, etc.
41
36
  `;
42
37
  }
@@ -1,27 +1,28 @@
1
1
  /**
2
2
  * Generate USER.md for an agent.
3
3
  * Pure function.
4
+ * Aligned with OpenClaw upstream template.
4
5
  */
5
6
  export function generateUser(agent, teamSpec) {
6
- const teamName = teamSpec.team?.name || '// TODO';
7
- const teamMission = teamSpec.team?.mission || '// TODO';
8
-
9
- return `# USER.md - About Your Human
7
+ return `# USER.md About Your Human
10
8
 
11
9
  - **Name:** // TODO
12
10
  - **What to call them:** // TODO
13
11
  - **Pronouns:** // TODO
14
12
  - **Timezone:** // TODO
15
- - **Notes:** // TODO
16
13
 
17
14
  ## Context
18
15
 
19
16
  // TODO: Learn about the person you're helping. Update this as you go.
20
17
 
21
- ## Team Context
18
+ - **Interests:** // TODO
19
+ - **Values:** // TODO
20
+ - **Active projects:** // TODO
21
+ - **Frustrations:** // TODO
22
+ - **Humor:** // TODO
23
+
24
+ ## Notes
22
25
 
23
- - **Team:** ${teamName}
24
- - **Team Mission:** ${teamMission}
25
- - **Your Role:** ${agent.mission || '// TODO'}
26
+ // TODO: Anything else that helps you be more helpful
26
27
  `;
27
28
  }
@@ -70,7 +70,17 @@ router.patch('/openclaw-config', (req, res) => {
70
70
  for (const newAgent of newAgents.list) {
71
71
  const idx = cfg.agents.list.findIndex(a => a.id === newAgent.id);
72
72
  if (idx >= 0) {
73
+ // Merge fields into existing agent entry
73
74
  if (newAgent.workspace) cfg.agents.list[idx].workspace = newAgent.workspace;
75
+ if (newAgent.agentDir) cfg.agents.list[idx].agentDir = newAgent.agentDir;
76
+ if (newAgent.name) cfg.agents.list[idx].name = newAgent.name;
77
+ if (newAgent.sandbox) cfg.agents.list[idx].sandbox = newAgent.sandbox;
78
+ if (newAgent.tools) {
79
+ cfg.agents.list[idx].tools = {
80
+ ...cfg.agents.list[idx].tools,
81
+ ...newAgent.tools,
82
+ };
83
+ }
74
84
  } else {
75
85
  cfg.agents.list.push(newAgent);
76
86
  }
@@ -1,51 +0,0 @@
1
- /**
2
- * Generate gateway/openclaw.routing.json5.
3
- * Pure function — outputs JSON5 string with // TODO comments for missing data.
4
- */
5
- export function generateRouting(teamSpec) {
6
- const { agents, routing, orchestration } = teamSpec;
7
- const defaultAgentId = routing?.defaultAgentId || orchestration?.router_agent || agents[0]?.id;
8
-
9
- const agentsList = agents.map(a => {
10
- const isDefault = a.id === defaultAgentId;
11
- const workspace = `~/.openclaw/workspace-${a.id}`;
12
- if (isDefault) {
13
- return ` { id: "${a.id}", default: true, workspace: "${workspace}" }`;
14
- }
15
- return ` { id: "${a.id}", workspace: "${workspace}" }`;
16
- }).join(',\n');
17
-
18
- const bindingsList = (routing?.bindings || []).map(b => {
19
- const matchParts = Object.entries(b.match)
20
- .map(([k, v]) => {
21
- if (typeof v === 'object') {
22
- return `${k}: ${JSON.stringify(v)}`;
23
- }
24
- return `${k}: "${v}"`;
25
- })
26
- .join(', ');
27
- return ` { agentId: "${b.agentId}", match: { ${matchParts} } }`;
28
- });
29
-
30
- const bindingsSection = bindingsList.length === 0
31
- ? ` // TODO: Add channel bindings\n // Example: { agentId: "${defaultAgentId}", match: { channel: "discord", accountId: "${defaultAgentId}" } }`
32
- : bindingsList.join(',\n');
33
-
34
- return `{
35
- // OpenClaw Gateway Routing Config
36
- // Generated by openclaw-agent-builder
37
- // Edit as needed — this is JSON5, so comments are supported.
38
-
39
- agents: {
40
- list: [
41
- ${agentsList}
42
- ]
43
- },
44
-
45
- // Bindings — sorted by specificity: peer > guildId > teamId > accountId-exact > accountId:* > default
46
- bindings: [
47
- ${bindingsSection}
48
- ]
49
- }
50
- `;
51
- }
@@ -1,58 +0,0 @@
1
- /**
2
- * Generate team/TEAM.md.
3
- * Pure function.
4
- */
5
- export function generateTeam(teamSpec) {
6
- const agentsTable = teamSpec.agents.map(a =>
7
- `| ${a.id} | ${a.name} | ${a.mission || '// TODO'} |`
8
- ).join('\n');
9
-
10
- const handoffGraph = (teamSpec.handoffs || []).length > 0
11
- ? teamSpec.handoffs.map(h =>
12
- `- **${h.from}** → **${h.to}**: ${h.when} (${h.payload_contract})`
13
- ).join('\n')
14
- : '// TODO: No handoffs defined';
15
-
16
- const sharedNever = (teamSpec.shared_constraints?.never || []).length > 0
17
- ? teamSpec.shared_constraints.never.map(r => `- **NEVER** ${r}`).join('\n')
18
- : '// TODO: Define shared constraints';
19
-
20
- const memoryMode = teamSpec.shared_memory?.mode || 'separate';
21
- const memoryLocation = teamSpec.shared_memory?.location || '// TODO';
22
-
23
- const teamName = teamSpec.team?.name ||
24
- (teamSpec.agents.length === 1 ? `${teamSpec.agents[0].name} Workspace` : '// TODO');
25
-
26
- return `# TEAM.md - Team Charter
27
-
28
- ## Team
29
-
30
- **${teamName}**
31
-
32
- ${teamSpec.team?.mission || '// TODO: Define team mission'}
33
-
34
- ## Agents
35
-
36
- | ID | Name | Mission |
37
- |----|------|---------|
38
- ${agentsTable}
39
-
40
- ## Orchestration
41
-
42
- - **Mode:** ${teamSpec.orchestration?.mode || '// TODO'}
43
- - **Router Agent:** ${teamSpec.orchestration?.router_agent || '// TODO'}
44
-
45
- ## Handoff Graph
46
-
47
- ${handoffGraph}
48
-
49
- ## Shared Constraints
50
-
51
- ${sharedNever}
52
-
53
- ## Memory Model
54
-
55
- - **Mode:** ${memoryMode}
56
- ${memoryMode === 'shared_summary' ? `- **Location:** ${memoryLocation}` : '- Each agent maintains their own MEMORY.md'}
57
- `;
58
- }