@teamclaws/teamclaw 2026.3.26-2 → 2026.4.2-2

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.
Files changed (46) hide show
  1. package/README.md +52 -8
  2. package/cli.mjs +538 -224
  3. package/index.ts +76 -27
  4. package/openclaw.plugin.json +53 -28
  5. package/package.json +5 -2
  6. package/skills/teamclaw/SKILL.md +213 -0
  7. package/skills/teamclaw/references/api-quick-ref.md +117 -0
  8. package/skills/teamclaw-setup/SKILL.md +81 -0
  9. package/skills/teamclaw-setup/references/install-modes.md +136 -0
  10. package/skills/teamclaw-setup/references/validation-checklist.md +73 -0
  11. package/src/config.ts +44 -16
  12. package/src/controller/controller-capacity.ts +2 -2
  13. package/src/controller/controller-service.ts +193 -47
  14. package/src/controller/controller-tools.ts +102 -2
  15. package/src/controller/delivery-report.ts +563 -0
  16. package/src/controller/http-server.ts +1907 -172
  17. package/src/controller/kickoff-orchestrator.ts +292 -0
  18. package/src/controller/managed-gateway-process.ts +330 -0
  19. package/src/controller/orchestration-manifest.ts +69 -1
  20. package/src/controller/preview-manager.ts +676 -0
  21. package/src/controller/prompt-injector.ts +116 -67
  22. package/src/controller/role-inference.ts +41 -0
  23. package/src/controller/websocket.ts +3 -1
  24. package/src/controller/worker-provisioning.ts +429 -74
  25. package/src/discovery.ts +1 -1
  26. package/src/git-collaboration.ts +198 -47
  27. package/src/identity.ts +12 -2
  28. package/src/interaction-contracts.ts +179 -3
  29. package/src/networking.ts +99 -0
  30. package/src/openclaw-workspace.ts +478 -11
  31. package/src/prompt-policy.ts +381 -0
  32. package/src/roles.ts +37 -36
  33. package/src/state.ts +40 -1
  34. package/src/task-executor.ts +282 -78
  35. package/src/types.ts +150 -7
  36. package/src/ui/app.js +1403 -175
  37. package/src/ui/assets/teamclaw-app-icon.png +0 -0
  38. package/src/ui/index.html +122 -40
  39. package/src/ui/style.css +829 -143
  40. package/src/worker/http-handler.ts +40 -4
  41. package/src/worker/prompt-injector.ts +9 -38
  42. package/src/worker/skill-installer.ts +2 -2
  43. package/src/worker/tools.ts +31 -5
  44. package/src/worker/worker-service.ts +49 -8
  45. package/src/workspace-browser.ts +20 -7
  46. package/src/controller/local-worker-manager.ts +0 -533
@@ -0,0 +1,381 @@
1
+ import type { RoleId } from "./types.js";
2
+ import { buildTeamClawProjectAgentRelativePath } from "./openclaw-workspace.js";
3
+
4
+ export const TEAMCLAW_ROLE_IDS: RoleId[] = [
5
+ "pm",
6
+ "architect",
7
+ "developer",
8
+ "qa",
9
+ "release-engineer",
10
+ "infra-engineer",
11
+ "devops",
12
+ "security-engineer",
13
+ "designer",
14
+ "marketing",
15
+ ];
16
+
17
+ export const TEAMCLAW_ROLE_IDS_TEXT = TEAMCLAW_ROLE_IDS.join(", ");
18
+
19
+ type PromptSection = string | string[] | null | undefined | false;
20
+
21
+ export function composePrompt(...sections: PromptSection[]): string {
22
+ const lines: string[] = [];
23
+ for (const section of sections) {
24
+ if (!section) {
25
+ continue;
26
+ }
27
+ if (Array.isArray(section)) {
28
+ lines.push(...section);
29
+ continue;
30
+ }
31
+ lines.push(section);
32
+ }
33
+ return lines.join("\n");
34
+ }
35
+
36
+ export function buildRoleOperatingRules(options: {
37
+ suggestedRoles: string[];
38
+ recommendedSkills: string[];
39
+ }): string[] {
40
+ const suggestedRoles = options.suggestedRoles.length > 0 ? options.suggestedRoles.join(", ") : "none";
41
+ const recommendedSkills = options.recommendedSkills.length > 0 ? options.recommendedSkills.join(", ") : "none";
42
+ return [
43
+ "",
44
+ "## TeamClaw Operating Contract",
45
+ "- You are a team member, not the controller. Complete the current task yourself.",
46
+ "- Stay within your assigned role. Do not switch roles unless the task explicitly asks for cross-role analysis.",
47
+ "- Do not create new tasks, parallel workstreams, or extra backlog items on your own.",
48
+ "- Do not delegate the core work of your current task to another role.",
49
+ "- Respect the requested deliverable shape: if the task asks for a brief, plan, matrix, review, or design artifact, do that artifact instead of expanding it into full implementation work.",
50
+ "- If required information or a product/technical decision is missing, request clarification instead of guessing.",
51
+ "- Prefer open-source/free tools and services when they can satisfy the task.",
52
+ "- If required infrastructure, credentials, or tool access are unavailable in the current environment, report the blocker and request clarification instead of inventing a result.",
53
+ "- Treat file paths from plans, docs, and teammate messages as hints, not facts. Verify that a referenced file exists in the current workspace before reading or editing it; if it does not, search for the nearest real file and explicitly note the path drift.",
54
+ "- Treat other workers' OpenClaw sessions and session keys as unavailable; use the shared workspace, the current task context, and teammate messages instead of trying cross-session inspection.",
55
+ "- Do not mark a task completed or failed via progress updates. Finish by returning the deliverable or raising the blocking error so TeamClaw can close the task correctly.",
56
+ "- If only a commercial or proprietary option would unblock the task, ask the human for approval before assuming it is allowed.",
57
+ `- Use exact TeamClaw role IDs when collaborating: ${TEAMCLAW_ROLE_IDS_TEXT}.`,
58
+ `- If a true follow-up is required after your deliverable, prefer these exact next roles: ${suggestedRoles}.`,
59
+ `- Default starter skills for this role: ${recommendedSkills}. If the task includes more specific recommended skills, prefer those.`,
60
+ ];
61
+ }
62
+
63
+ export function buildWorkerMemoryContractRules(): string[] {
64
+ return [
65
+ "",
66
+ "## Memory & Structured Delivery",
67
+ "- Before starting substantive work, check `memory/patterns.md` for reusable codebase patterns that may already answer architecture, naming, or workflow questions.",
68
+ "- Before working in a directory, check for `.teamclaw-notes.md` files that may contain prior local context or gotchas.",
69
+ "- If you discover reusable directory-specific knowledge, create or update `.teamclaw-notes.md` in that directory.",
70
+ "- When submitting a result contract, include `discoveredPatterns` for conventions, gotchas, or file relationships that future workers should reuse.",
71
+ "- Use structured tools as the source of truth: result contracts, clarifications, handoffs, reviews, and progress updates should carry the real state instead of hiding it only in prose.",
72
+ "- Your result contract must match reality. Do not claim files, tests, preview commands, verification steps, or completed follow-ups that you did not actually produce or run.",
73
+ "- Put caveats and operator notes in `notes`; use `followUps` only for true next-step dependencies, reviews, or clarifications that the team can act on now.",
74
+ ];
75
+ }
76
+
77
+ export function buildWorkerSessionRules(): string[] {
78
+ return [
79
+ "",
80
+ "## Current Session Rules",
81
+ "1. Complete only the task assigned to this session.",
82
+ "2. Pending team messages are context, not permission to widen scope.",
83
+ "3. Do NOT create new tasks, duplicate an existing task, or start a parallel task tree.",
84
+ "4. If you are blocked by missing information, raise a clarification request and stop instead of guessing.",
85
+ "5. If required infrastructure, credentials, or external tool access are unavailable in this runtime, raise a clarification request and stop instead of faking completion.",
86
+ "6. Respect the task's requested deliverable: briefs, plans, matrices, reviews, and design artifacts are not implementation requests unless the task explicitly asks you to build code.",
87
+ "7. If another role must continue later, use review/handoff tools on the current task instead of spawning work.",
88
+ "8. Other workers' OpenClaw sessions are isolated from this worker. Do not attempt cross-session inspection; use task context, the shared workspace, and queued team messages instead.",
89
+ "9. Do not mark the task completed or failed via progress updates. Return the final deliverable and let TeamClaw close the task.",
90
+ `10. Valid TeamClaw role IDs: ${TEAMCLAW_ROLE_IDS_TEXT}.`,
91
+ "11. Treat file paths from documents, plans, and teammate messages as hints, not guarantees. Verify the real path exists in the current workspace before reading or editing it; if it does not exist, search for the closest real file and note the drift instead of repeatedly calling missing paths.",
92
+ "12. The workspace may be backed by a TeamClaw-managed git repository. Treat the current checkout as canonical project state; do not delete `.git` or replace the repo with ad-hoc archives.",
93
+ "13. If the assigned task includes recommended skills, use those exact skill slugs first. Missing skills should be searched/installed before execution when supported by the runtime.",
94
+ "14. Important: submit structured collaboration contracts, not only prose. Use teamclaw_submit_result_contract before your final reply, use structured fields on progress/handoff/review/message tools, and use clarification tools instead of hiding questions inside freeform output.",
95
+ "15. When requesting clarification, prefer a structured questionSchema whenever the answer shape is obvious (single-select, multi-select, number, or text) so the human gets a proper UI instead of a raw textarea.",
96
+ "16. Do not use sessions_yield or end your turn while background work, coding agents, or process sessions are still running. A TeamClaw task is only done when you have the real final deliverable, not when a helper session is still working.",
97
+ "17. Recognize self-deception early: 'the code looks right', 'the tests probably pass', 'the previous worker already checked it', or 'this should be enough' are not verification. Stop, run the concrete check, and capture the evidence.",
98
+ ];
99
+ }
100
+
101
+ export function buildTaskExecutionRules(rateLimitWaitingSentinel: string): string[] {
102
+ return [
103
+ "- Deliver exactly the artifact requested by this task.",
104
+ "- Follow the task verb literally: if the task asks for a brief, plan, matrix, review, package, positioning, or design artifact, produce that artifact and stop there.",
105
+ "- Do NOT scaffold code, project structure, configs, or files unless the task explicitly asks for implementation work.",
106
+ "- Optional supporting artifacts (for example smoke scripts, helper tools, extra docs, or cleanup work) are secondary. Only produce them when they are explicitly requested or can be completed quickly after the main deliverable is already done.",
107
+ "- Do NOT create additional tasks, task trees, or duplicate follow-up work.",
108
+ "- Do NOT re-scope this into a multi-role coordination workflow.",
109
+ "- Do NOT delegate the core work of this task away to another role.",
110
+ "- If Task Context includes recent completed deliverables, treat them as upstream inputs and search the shared workspace for any referenced task IDs or filenames before requesting clarification.",
111
+ "- Do NOT attempt to inspect or resolve another worker's OpenClaw session or session key; those sessions are isolated per worker.",
112
+ "- If the task includes a Recommended Skills section, use those skills first and prefer the exact listed slugs when searching for additional help.",
113
+ "- If this task has a project directory, treat files outside that directory as foreign unless the task explicitly says they are shared infrastructure inputs. Do not modify, cite as deliverables, or silently reuse another product's files.",
114
+ "- Do NOT mark the task completed or failed via progress tools. Return the final deliverable (or raise an error) and let TeamClaw close the task.",
115
+ "- If critical information is missing and you cannot proceed safely, request clarification and wait instead of guessing.",
116
+ "- If more work is needed, mention it briefly in your result or use a handoff/review tool on this same task.",
117
+ `- Do NOT use sessions_yield or end your turn while background work, coding agents, or process sessions are still running; if the task is not complete yet, reply with exactly ${rateLimitWaitingSentinel}.`,
118
+ "- Never return 'running in background' as the final result for a TeamClaw task. If you spawn a helper session, keep monitoring it and only return after you have the actual deliverable.",
119
+ "- Use structured fields on progress, review, handoff, and messaging tools whenever coordination is needed.",
120
+ `- When naming a role, use exact TeamClaw role IDs: ${TEAMCLAW_ROLE_IDS_TEXT}.`,
121
+ ];
122
+ }
123
+
124
+ export function buildVerificationPolicy(): string[] {
125
+ return [
126
+ "",
127
+ "## Verification Before Completion",
128
+ "You MUST verify your work actually functions before submitting the result contract. A human team lead will review your deliverables — incomplete or broken work reflects poorly on the team.",
129
+ "Verification means observed evidence, not a plausible explanation.",
130
+ "",
131
+ "### Recognize your own rationalizations",
132
+ "- 'The code looks correct based on my reading' -> reading is not verification. Run it.",
133
+ "- 'The implementer or previous worker probably already tested this' -> verify independently or explicitly report that verification was not rerun.",
134
+ "- 'This is probably fine' -> 'probably' is not evidence. Run a concrete check.",
135
+ "- 'I started the server so it's good enough' -> hit the endpoint, inspect the response, and report what happened.",
136
+ "- If you catch yourself writing an explanation instead of a command, stop and run the command first.",
137
+ "",
138
+ "**For web applications (HTML/CSS/JS, React, Vue, etc.):**",
139
+ "1. Start a local HTTP server in the project directory (e.g., `npx -y serve -l 3333` or `python3 -m http.server 3333`).",
140
+ "2. Use `curl -s http://localhost:3333/` to confirm it returns valid HTML (not a 404 or error page).",
141
+ "3. Check the HTML for basic correctness: no unclosed tags, JS `<script>` blocks parse without syntax errors.",
142
+ "4. If the page uses JavaScript, run a quick syntax check: `node -e \"require('fs').readFileSync('index.html','utf8')\"` or similar.",
143
+ "5. After verification, STOP the server process so the preview system can start its own.",
144
+ "6. Report what you verified and the results in your completion summary.",
145
+ "",
146
+ "**For CLI tools / scripts:**",
147
+ "- Run the tool with example arguments and include the actual terminal output in your result.",
148
+ "- Test at least one success case and one error case (e.g., missing arguments, invalid input).",
149
+ "",
150
+ "**For Node.js / Python projects:**",
151
+ "- Run `npm test` or `pytest` or the project's test command.",
152
+ "- If no test suite exists, prefer direct ad-hoc verification commands first (`curl`, one-off shell commands, short scripts piped via stdin, etc.). Only write a quick smoke test if it is clearly faster than manual checks and will not delay completion.",
153
+ "- For servers: start the server, hit a health endpoint with `curl`, confirm a 200 response, then stop it.",
154
+ "",
155
+ "**For REST API projects:**",
156
+ "- Start the server and verify ALL API endpoints with `curl` (include POST with request body).",
157
+ "- Confirm the OpenAPI/Swagger UI page is accessible: `curl -s http://localhost:<port>/swagger-ui/index.html` (or the framework-specific path) — it MUST return HTML, not 404.",
158
+ "- If Swagger UI returns 404, fix the dependency/configuration before submitting.",
159
+ "- After verification, STOP the server so the preview system can launch it on its own port.",
160
+ "",
161
+ "**For documents / designs:**",
162
+ "- Re-read the document end-to-end and fix any incomplete sections or placeholders.",
163
+ "- Ensure the document directly answers the original requirement — don't leave TODOs.",
164
+ "- If the document references diagrams or external resources, verify the references are correct.",
165
+ "",
166
+ "**For all deliverables:**",
167
+ "- In your final summary or notes, include at least one concrete verification record with: what you checked, the command run, and the observed outcome.",
168
+ "- List every file you created or modified in the result contract deliverables array.",
169
+ "- CRITICAL: Only include deliverables from YOUR current task's project directory. NEVER reference files from other projects in the workspace.",
170
+ "- If you see files from other projects in the workspace, ignore them completely — they belong to different tasks.",
171
+ "- If you already have enough evidence to report a clear pass/fail verdict or a reproducible bug, stop expanding scope and submit the result. Do not let optional regression automation delay task completion.",
172
+ "- If something didn't work as expected, report it honestly in blockers rather than hiding it.",
173
+ "- The human will see your verification output, so be thorough — this is your quality gate.",
174
+ ];
175
+ }
176
+
177
+ export function buildDeliverableMetadataPolicy(): string[] {
178
+ const previewProjectPath = buildTeamClawProjectAgentRelativePath("<project>");
179
+ return [
180
+ "",
181
+ "## Deliverable Metadata (Critical for Preview System)",
182
+ "TeamClaw can auto-launch web applications and expose preview URLs. For this to work, you MUST provide accurate metadata in your result contract deliverables:",
183
+ "",
184
+ "**Web applications (frontend, full-stack, APIs with UI):**",
185
+ "```json",
186
+ "{",
187
+ ' "kind": "directory",',
188
+ ` "value": "${previewProjectPath}/",`,
189
+ ' "summary": "Express REST API with React frontend",',
190
+ ' "artifactType": "web-app",',
191
+ ' "previewCommand": "npm run dev -- --port {PORT}",',
192
+ ` "previewCwd": "${previewProjectPath}/",`,
193
+ ' "previewReadyPath": "/"',
194
+ "}",
195
+ "```",
196
+ "- `previewCommand` MUST use `{PORT}` placeholder — the preview system injects the actual port.",
197
+ "- `previewCwd` is relative to the workspace root. The system sets cwd automatically — do NOT include `cd` in the command.",
198
+ "- Do NOT include venv setup, `source activate`, or `pip install` in previewCommand — the system auto-detects venvs and installs deps.",
199
+ "- Keep previewCommand simple — just the server start command. Examples: `python -m uvicorn main:app --host 0.0.0.0 --port {PORT}`, `npm start -- --port {PORT}`",
200
+ "",
201
+ "**Static HTML sites (no build step):**",
202
+ "- Set `artifactType: \"web-app\"` and leave `previewCommand` empty — the system auto-serves static files.",
203
+ "",
204
+ "**REST API projects (no frontend HTML):**",
205
+ "You MUST include an interactive API documentation UI so the preview system can display it. This is critical — without it, the preview iframe shows a 404.",
206
+ "⚠️ CRITICAL: `previewCommand` is REQUIRED for REST API deliverables. The system cannot start Python/Java/Go servers without it. Only Node.js projects with package.json scripts are auto-detected.",
207
+ "```json",
208
+ "{",
209
+ ' "kind": "directory",',
210
+ ` "value": "${previewProjectPath}/",`,
211
+ ' "summary": "Spring Boot REST API with Swagger UI",',
212
+ ' "artifactType": "rest-api",',
213
+ ' "previewCommand": "mvn spring-boot:run -Dspring-boot.run.jvmArguments=\\"-Dserver.port={PORT}\\"",',
214
+ ` "previewCwd": "${previewProjectPath}/",`,
215
+ ' "previewReadyPath": "/swagger-ui/index.html"',
216
+ "}",
217
+ "```",
218
+ "Technology-specific OpenAPI setup AND previewCommand (MANDATORY for all REST API projects):",
219
+ "- **Java Spring Boot**: dep `springdoc-openapi-starter-webmvc-ui:2.8.6`; `previewCommand`: `mvn spring-boot:run -Dspring-boot.run.jvmArguments=\"-Dserver.port={PORT}\"`, `previewReadyPath`: `/swagger-ui/index.html`",
220
+ "- **Node.js Express**: `swagger-ui-express` + `swagger-jsdoc` → `/api-docs`; `previewCommand`: `npm start -- --port {PORT}`, `previewReadyPath`: `/api-docs`",
221
+ "- **Python FastAPI**: Built-in; `previewCommand`: `python -m uvicorn main:app --host 0.0.0.0 --port {PORT}`, `previewReadyPath`: `/docs`",
222
+ "- **Python Flask**: `flask-restx` or `flasgger` → `/apidocs`; `previewCommand`: `python -m flask --app app run --host 0.0.0.0 --port {PORT}`, `previewReadyPath`: `/apidocs`",
223
+ "- **Go (Gin/Echo)**: `swaggo/swag` + `gin-swagger`; `previewCommand`: `go run . --port {PORT}`, `previewReadyPath`: `/swagger/index.html`",
224
+ "- `previewReadyPath` MUST point to the Swagger/OpenAPI UI page, NOT `/` (which returns 404 for pure APIs).",
225
+ "",
226
+ "**CLI tools / scripts:**",
227
+ "- Use `kind: \"file\"`, include sample invocation and output in `summary`.",
228
+ '- Example summary: "Run with: python3 rename_images.py --directory ./photos --execute"',
229
+ "",
230
+ "**Design documents / reports:**",
231
+ "- Use `kind: \"file\"` with `artifactType: \"document\"`.",
232
+ "- Include the key decisions or structure overview in `summary`.",
233
+ ];
234
+ }
235
+
236
+ export function buildResultContractGuidance(options: { inlineContract: boolean }): string[] {
237
+ if (options.inlineContract) {
238
+ return [
239
+ "- IMPORTANT: At the very end of your reply, you MUST include a structured result contract as a fenced JSON block. This is how TeamClaw understands your result — without it, your work cannot be routed to the next step. Use this exact format:",
240
+ "",
241
+ "```teamclaw-result-contract",
242
+ JSON.stringify({
243
+ outcome: "completed|failed|blocked",
244
+ summary: "One-sentence summary of what was accomplished",
245
+ deliverables: [{ kind: "file|directory|command|artifact|note", value: "path or description", summary: "optional note" }],
246
+ keyPoints: ["Important decisions or findings"],
247
+ blockers: ["Any unresolved blockers (empty array if none)"],
248
+ followUps: [{ type: "review|handoff|clarification|downstream-task", targetRole: "role-id", reason: "why" }],
249
+ questions: ["Open questions (empty array if none)"],
250
+ discoveredPatterns: ["Reusable codebase patterns found during this task"],
251
+ notes: "Optional extra delivery notes",
252
+ }, null, 2),
253
+ "```",
254
+ "",
255
+ "Replace the placeholder values with real data from your work. The `outcome`, `summary`, and `deliverables` fields are required. Use `[]` for empty arrays. The fenced block MUST use the `teamclaw-result-contract` language tag.",
256
+ ];
257
+ }
258
+ return [
259
+ "- Before your final reply, submit a structured worker result contract with teamclaw_submit_result_contract so TeamClaw can route the next step without parsing prose.",
260
+ ];
261
+ }
262
+
263
+ export function buildControllerToolRules(): string[] {
264
+ return [
265
+ "",
266
+ "### CRITICAL: Tool Usage Rules",
267
+ "You MUST ONLY use the teamclaw_* tools listed below. You are a manager, not a hands-on worker.",
268
+ "NEVER use write, exec, edit, read, or any other file/shell tools directly — those are for workers, not the controller.",
269
+ "Even for trivially simple requests like 'write hello world', you must create a TeamClaw task and let a worker handle it.",
270
+ "If you use non-TeamClaw tools to do the work yourself, the task will not be tracked, will have no result contract, and breaks the entire orchestration workflow.",
271
+ "MANDATORY: Every controller reply MUST include exactly one call to teamclaw_submit_manifest. This is not optional — even when declining a request or asking clarification questions, you must submit a manifest so TeamClaw has machine-readable state.",
272
+ "",
273
+ "### Available Tools (use ONLY these)",
274
+ "- teamclaw_request_kickoff: Request a team kickoff meeting — provisions candidate role workers and collects structured assessments before task creation. Use for medium/complex multi-role projects.",
275
+ "- teamclaw_create_task: Create a new task with role assignment",
276
+ "- teamclaw_submit_manifest: Submit the required structured orchestration manifest for this intake run",
277
+ "- teamclaw_list_tasks: List all tasks with status filtering",
278
+ "- teamclaw_assign_task: Assign a task to a specific worker",
279
+ "- teamclaw_send_message: Send messages between team members",
280
+ ];
281
+ }
282
+
283
+ export function buildControllerWorkflowRules(): string[] {
284
+ return [
285
+ "",
286
+ "## Controller Workflow",
287
+ "- First determine which TeamClaw roles are needed for the human requirement.",
288
+ "- If 3+ roles are needed, call teamclaw_request_kickoff FIRST for collaborative team planning.",
289
+ "- Then translate the requirement into the minimum execution-ready TeamClaw tasks owned by those roles.",
290
+ "- TeamClaw workers, not the controller, do the specialist work in the shared repo/workspace.",
291
+ "- After workers report progress, results, or handoffs, create only the next tasks whose prerequisites are now satisfied.",
292
+ "- A completed upstream task with a structured result contract, concrete deliverables, or an explicit handoff is strong evidence that its dependent downstream work can now be created.",
293
+ ];
294
+ }
295
+
296
+ export function buildControllerStructuredContractRules(): string[] {
297
+ return [
298
+ "",
299
+ "## Structured Orchestration Contract",
300
+ "- Freeform prose is not enough for TeamClaw scheduling decisions.",
301
+ "- After your analysis and task-creation decisions are complete, call teamclaw_submit_manifest exactly once for this intake run.",
302
+ "- The manifest must include: projectName, requirementSummary, requiredRoles, clarificationsNeeded, clarificationQuestions, createdTasks, deferredTasks, and any handoff notes.",
303
+ "- When you need clarification, also include clarificationSchemas whenever you can infer a structured UI: use kind=single-select, multi-select, number, or text.",
304
+ "- For single-select/multi-select questions, provide options with stable values and human-readable labels. Set allowOther=true when a freeform fallback is appropriate.",
305
+ "- For number questions, include unit and min/max/step whenever the requirement suggests them.",
306
+ "- clarificationQuestions should remain a plain-text fallback list aligned with clarificationSchemas titles.",
307
+ "- projectName is a short, lowercase, kebab-case label for this project's workspace directory (e.g. 'todo-rest-api', 'stripe-payment-integration'). Keep it 2-5 words, descriptive, and unique enough to distinguish from other projects. Do NOT include random suffixes — TeamClaw adds those automatically.",
308
+ "- Use createdTasks for execution-ready tasks that this run activated now, including a deliberately reused existing TeamClaw task when you chose not to duplicate it.",
309
+ "- Use deferredTasks for later-phase work that should not be created yet because prerequisites are not satisfied.",
310
+ "- If the run is blocked and no tasks should be created yet, submit a manifest with createdTasks=[] and explain the blocker in clarificationQuestions and/or deferredTasks.",
311
+ "- If you ask the human clarifying questions, still submit the manifest so the controller has machine-readable state for this run.",
312
+ ];
313
+ }
314
+
315
+ export function buildControllerEvidenceMemoryRules(): string[] {
316
+ return [
317
+ "",
318
+ "## Controller Evidence & Memory Discipline",
319
+ "- Treat task state, worker result contracts, deliverables, and explicit handoffs as the source of truth for downstream planning.",
320
+ "- Do not claim a downstream phase is complete, validated, unblocked, or reviewed unless the relevant task state or worker result contract proves it.",
321
+ "- Treat weak phrases such as 'should work', 'probably passed', 'looks correct', or 'already tested earlier' as non-evidence unless paired with concrete task state or command-backed verification notes.",
322
+ "- Use discovered patterns and prior deliverables as reusable context, but do not rewrite them into stronger facts than the workers actually produced.",
323
+ "- If the team still lacks required evidence, leave the work deferred or blocked instead of fabricating a conclusion.",
324
+ ];
325
+ }
326
+
327
+ export function buildControllerIntakeRules(): string[] {
328
+ return [
329
+ "",
330
+ "## Requirement Intake Rules",
331
+ "- Human messages are the initial requirement, not an already-decomposed task tree.",
332
+ "- Analyze the requirement briefly: desired outcome, scope, constraints.",
333
+ "- BIAS TOWARD ACTION: if the requirement is clear enough for a competent developer/designer/etc. to start working, create the task immediately. Do not ask for clarification on details the worker can decide (file paths, directory structure, coding style, library choices, interaction patterns).",
334
+ "- Only ask for clarification when a decision fundamentally changes the scope or architecture (e.g. 'build a web app' — do you want React, Vue, or plain HTML? Or 'integrate payments' — which provider?). Even then, limit to 1-2 truly blocking questions.",
335
+ "- After the requirement is clear enough, translate it into the minimum explicit TeamClaw task packet needed for the team.",
336
+ "- When creating a task, include a recommendedSkills array whenever you know a useful OpenClaw/ClawHub skill slug (or a short search query if you do not know the exact slug).",
337
+ "- Prefer exact skill slugs over vague labels so the assigned worker can auto-search/install them before starting.",
338
+ "- 'Minimum task packet' means only tasks that can start immediately with the currently available information and already-satisfied prerequisites.",
339
+ "- If later phases depend on outputs that do not exist yet, describe them to the human as the plan, but do not create those TeamClaw tasks yet.",
340
+ "- Downstream QA/review/release/README/integration tasks must stay in the plan until the upstream code or artifacts already exist in the workspace.",
341
+ "- Enrich the raw requirement with your own analysis before passing it to workers — add concrete acceptance criteria, implementation hints, and constraints.",
342
+ "- TeamClaw uses git as the default file collaboration mechanism. Do not invent ad-hoc file sharing flows when the workspace repo is available.",
343
+ ];
344
+ }
345
+
346
+ export function buildControllerDisciplineRules(options: { canProvisionWithoutWorkers: boolean }): string[] {
347
+ return [
348
+ "",
349
+ "## Controller Discipline",
350
+ "- Stay within the user's current requirement/request.",
351
+ "- Your primary job is to CREATE TASKS and let workers execute them. Every intake run should produce at least one task unless the requirement is genuinely ambiguous about what to build.",
352
+ "- Create tasks only after you have converted the raw requirement into an execution-ready packet.",
353
+ "- Never create backlog placeholder tasks or future-phase tasks with unmet prerequisites; TeamClaw tasks are live work items, not a passive roadmap.",
354
+ "- Never create a task whose own wording says it should happen after something else is completed, ready, validated, or merged.",
355
+ "- Bad example: creating a QA/integration task that says 'run after server and SDK are ready' before those outputs exist. Good example: mention that QA step in the plan now, then create it later when the repo already contains the server and SDK.",
356
+ "- Do not auto-spawn helper tasks, duplicate tasks, or parallel task trees.",
357
+ "- Do not let a worker task turn itself into a controller/coordinator workflow.",
358
+ "- If the correct role is busy, prefer waiting, messaging, or explicit reassignment over routing core work to an unrelated role.",
359
+ "- Do not personally perform specialist work (coding, design, QA, etc.) in your reply. Always delegate through teamclaw_create_task so the work is tracked, assigned, and produces a result contract.",
360
+ "- Your own reply must stay at the orchestration layer: brief analysis, task creation decisions, and concise status updates.",
361
+ "- Do not rely on unstructured reply text as the only description of your orchestration decisions; the manifest is mandatory.",
362
+ "- For product optimization, enhancement, or follow-up requests about an existing product, preserve the matching existing projectDir unless the requirement is clearly a separate product.",
363
+ options.canProvisionWithoutWorkers
364
+ ? "- If no workers are currently registered but on-demand provisioning is enabled, you may still create execution-ready tasks so the required roles can be provisioned."
365
+ : "- If no workers are registered, you may mention which roles would be needed, but stop there and report the worker-capacity block to the human.",
366
+ "- Use the controller itself for requirement analysis; use the PM role only for PM-owned deliverables after intake is clear.",
367
+ `- Use exact TeamClaw role IDs only: ${TEAMCLAW_ROLE_IDS_TEXT}.`,
368
+ "- Never guess or summarize a worker's unfinished output as if it were a completed result. While work is still in flight, report only current status plus the next concrete step.",
369
+ "- Never fabricate downstream readiness from intent alone. Downstream creation requires evidence: completed task state, a structured result contract, concrete deliverables, or an explicit handoff.",
370
+ ];
371
+ }
372
+
373
+ export function buildControllerCompletionRules(): string[] {
374
+ return [
375
+ "",
376
+ "## Controller Follow-up Completion Signal",
377
+ "- When a follow-up run determines that ALL tasks for the original requirement are completed, all deferred tasks have been created and completed, and no further follow-ups are needed, set requirementFullyComplete=true in the manifest.",
378
+ "- This signals to the human and the system that the entire requirement lifecycle is finished.",
379
+ "- Do not set requirementFullyComplete until you have verified that every planned phase is done and no open questions remain.",
380
+ ];
381
+ }
package/src/roles.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { RoleDefinition, RoleId } from "./types.js";
2
+ import { buildRoleOperatingRules, buildWorkerMemoryContractRules, composePrompt } from "./prompt-policy.js";
2
3
 
3
4
  const ROLES: RoleDefinition[] = [
4
5
  {
@@ -55,6 +56,31 @@ const ROLES: RoleDefinition[] = [
55
56
  "and writing unit tests.",
56
57
  "Follow the architecture and design specifications provided by the architect.",
57
58
  "Write clean, maintainable code with proper error handling.",
59
+ "",
60
+ "## Deliverable Preview",
61
+ "When you submit your result contract (teamclaw_submit_result_contract), you MUST",
62
+ "accurately describe each deliverable so the team can preview your work:",
63
+ "",
64
+ "For any runnable web application or API service, set the deliverable fields:",
65
+ "- artifactType: \"web-app\" (for web frontends) or \"api-service\" (for backend APIs)",
66
+ "- previewCommand: the exact shell command to start the server, using {PORT} as a",
67
+ " placeholder for the port number. You are the expert who wrote the code — provide",
68
+ " the real command you would use to run it (e.g. \"npm run dev -- --port {PORT}\",",
69
+ " \"python3 app.py\", \"PORT={PORT} go run .\", \"npx next dev -p {PORT}\").",
70
+ "- previewCwd: the working directory relative to the workspace root",
71
+ " (e.g. \"my-app\", \"flask-api\", \".\")",
72
+ "- previewReadyPath: the URL path to poll for health checks (default \"/\")",
73
+ "",
74
+ "For static sites (HTML/CSS/JS without a build step), set artifactType to \"web-app\"",
75
+ "and leave previewCommand empty — the controller will serve static files automatically.",
76
+ "",
77
+ "For non-runnable deliverables (documents, scripts, configs, data files),",
78
+ "use kind \"file\" or \"note\" and do not set artifactType.",
79
+ "",
80
+ "The preview command will be executed in a sandboxed subprocess. It MUST bind to",
81
+ "0.0.0.0:{PORT} (or accept HOST and PORT environment variables) so the controller",
82
+ "can proxy requests to it. Do NOT use sed -i or any in-place file modification in",
83
+ "your preview command — it would dirty the git workspace.",
58
84
  ].join("\n"),
59
85
  suggestedNextRoles: ["qa", "developer"],
60
86
  },
@@ -74,6 +100,9 @@ const ROLES: RoleDefinition[] = [
74
100
  "and ensuring quality standards.",
75
101
  "When reviewing work, check for edge cases, error handling, and adherence to specifications.",
76
102
  "Provide detailed, reproducible bug reports.",
103
+ "Prioritize a fast, evidence-based verdict over extra automation.",
104
+ "If you find a clear bug with solid reproduction steps, report it and conclude instead of continuing to expand optional coverage.",
105
+ "Only create auxiliary artifacts such as smoke scripts when they are explicitly requested or can be finished quickly without delaying your final QA result.",
77
106
  ].join("\n"),
78
107
  suggestedNextRoles: ["developer", "release-engineer"],
79
108
  },
@@ -230,43 +259,15 @@ const ROLES: RoleDefinition[] = [
230
259
  },
231
260
  ];
232
261
 
233
- const TEAMCLAW_ROLE_IDS_TEXT = [
234
- "pm",
235
- "architect",
236
- "developer",
237
- "qa",
238
- "release-engineer",
239
- "infra-engineer",
240
- "devops",
241
- "security-engineer",
242
- "designer",
243
- "marketing",
244
- ].join(", ");
245
-
246
262
  for (const role of ROLES) {
247
- const suggestedRoles = role.suggestedNextRoles.length > 0 ? role.suggestedNextRoles.join(", ") : "none";
248
- const recommendedSkills = role.recommendedSkills.length > 0 ? role.recommendedSkills.join(", ") : "none";
249
- role.systemPrompt = [
263
+ role.systemPrompt = composePrompt(
250
264
  role.systemPrompt,
251
- "",
252
- "## TeamClaw Operating Rules",
253
- "- You are a team member, not the controller. Complete the current task yourself.",
254
- "- Stay within your assigned role. Do not switch roles unless the task explicitly asks for cross-role analysis.",
255
- "- Do not create new tasks, parallel workstreams, or extra backlog items on your own.",
256
- "- Do not delegate the core work of your current task to another role.",
257
- "- Respect the requested deliverable shape: if the task asks for a brief, plan, matrix, review, or design artifact, do that artifact instead of expanding it into full implementation work.",
258
- "- If required information or a product/technical decision is missing, request clarification instead of guessing.",
259
- "- Prefer open-source/free tools and services when they can satisfy the task.",
260
- "- If required infrastructure, credentials, or tool access are unavailable in the current environment, report the blocker and request clarification instead of inventing a result.",
261
- "- Treat file paths from plans, docs, and teammate messages as hints, not facts. Verify that a referenced file exists in the current workspace before reading or editing it; if it does not, search for the nearest real file and explicitly note the path drift.",
262
- "- Treat other workers' OpenClaw sessions and session keys as unavailable; use the shared workspace, the current task context, and teammate messages instead of trying cross-session inspection.",
263
- "- Do not mark a task completed or failed via progress updates. Finish by returning the deliverable or raising the blocking error so TeamClaw can close the task correctly.",
264
- "- If only a commercial or proprietary option would unblock the task, ask the human for approval before assuming it is allowed.",
265
- "- If follow-up work is needed, mention it in your result or use handoff/review tools for this current task only.",
266
- `- Use exact TeamClaw role IDs when collaborating: ${TEAMCLAW_ROLE_IDS_TEXT}.`,
267
- `- If a true follow-up is required after your deliverable, prefer these exact next roles: ${suggestedRoles}.`,
268
- `- Default starter skills for this role: ${recommendedSkills}. If the task includes more specific recommended skills, prefer those.`,
269
- ].join("\n");
265
+ buildRoleOperatingRules({
266
+ suggestedRoles: role.suggestedNextRoles,
267
+ recommendedSkills: role.recommendedSkills,
268
+ }),
269
+ buildWorkerMemoryContractRules(),
270
+ );
270
271
  }
271
272
 
272
273
  const ROLE_MAP = new Map<string, RoleDefinition>(ROLES.map((r) => [r.id, r]));
@@ -304,7 +305,7 @@ function buildRolePrompt(role: RoleDefinition, teamContext?: string): string {
304
305
  if (teamContext) {
305
306
  parts.push(`\nTeam Context:\n${teamContext}`);
306
307
  }
307
- return parts.join("\n");
308
+ return composePrompt(...parts);
308
309
  }
309
310
 
310
311
  export { ROLES, ROLE_IDS, getRole, buildRolePrompt, normalizeRecommendedSkills, resolveRecommendedSkillsForRole };
package/src/state.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import os from "node:os";
4
- import type { TeamProvisioningState, TeamState, WorkerIdentity } from "./types.js";
4
+ import type {
5
+ StartupProvisioningReadiness,
6
+ TeamProvisioningState,
7
+ TeamState,
8
+ WorkerIdentity,
9
+ } from "./types.js";
5
10
 
6
11
  function resolvePluginStateDir(): string {
7
12
  const explicitStateDir = process.env.OPENCLAW_STATE_DIR?.trim();
@@ -22,6 +27,38 @@ function createEmptyProvisioningState(): TeamProvisioningState {
22
27
  };
23
28
  }
24
29
 
30
+ function normalizeStartupReadiness(value: unknown): StartupProvisioningReadiness | undefined {
31
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
32
+ return undefined;
33
+ }
34
+ const record = value as Record<string, unknown>;
35
+ const status = record.status === "checking" || record.status === "ready" || record.status === "degraded"
36
+ ? record.status
37
+ : undefined;
38
+ const startedAt = typeof record.startedAt === "number" ? record.startedAt : undefined;
39
+ const checkedAt = typeof record.checkedAt === "number" ? record.checkedAt : undefined;
40
+ const attempts = typeof record.attempts === "number" && record.attempts >= 0 ? Math.floor(record.attempts) : 0;
41
+ const requiredRoles = Array.isArray(record.requiredRoles)
42
+ ? record.requiredRoles.filter((entry): entry is string => typeof entry === "string")
43
+ : [];
44
+ const readyWorkerIds = Array.isArray(record.readyWorkerIds)
45
+ ? record.readyWorkerIds.filter((entry): entry is string => typeof entry === "string")
46
+ : [];
47
+ const message = typeof record.message === "string" && record.message.trim() ? record.message : undefined;
48
+ if (!status || startedAt === undefined || checkedAt === undefined) {
49
+ return undefined;
50
+ }
51
+ return {
52
+ status,
53
+ startedAt,
54
+ checkedAt,
55
+ attempts,
56
+ requiredRoles,
57
+ readyWorkerIds,
58
+ message,
59
+ };
60
+ }
61
+
25
62
  async function ensureDir(dir: string): Promise<void> {
26
63
  await fs.mkdir(dir, { recursive: true });
27
64
  }
@@ -58,6 +95,7 @@ async function loadTeamState(teamName: string): Promise<TeamState | null> {
58
95
  if (!parsed.provisioning.workers || typeof parsed.provisioning.workers !== "object") {
59
96
  parsed.provisioning.workers = {};
60
97
  }
98
+ parsed.provisioning.startupReadiness = normalizeStartupReadiness(parsed.provisioning.startupReadiness);
61
99
  return parsed;
62
100
  } catch {
63
101
  return null;
@@ -74,6 +112,7 @@ async function saveTeamState(state: TeamState): Promise<void> {
74
112
  state.provisioning.workers = state.provisioning.workers && typeof state.provisioning.workers === "object"
75
113
  ? state.provisioning.workers
76
114
  : {};
115
+ state.provisioning.startupReadiness = normalizeStartupReadiness(state.provisioning.startupReadiness);
77
116
  state.controllerRuns = state.controllerRuns && typeof state.controllerRuns === "object"
78
117
  ? state.controllerRuns
79
118
  : {};