Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Record image-affecting changes to `manager/`, `worker/`, `copaw/`, `openclaw-bas
- **Legacy Team channel policy**: Legacy Team reconciliation now writes final Matrix channel allow-lists to member runtime config and re-adds the Team Leader to the Manager allow-list so controller integration tests observe durable policy state.
- **Sandbox worker-deps hardening**: Sandbox-backed Workers now prepare controller-owned worker-deps env/token/data material before claim creation, recycle stale SandboxClaims and bound Sandboxes on runtime-affecting changes, and use bounded ServiceAccount token projection for built-in SandboxClaim mounts.
- **CLI AgentTeams auth env**: The `hiclaw` CLI now discovers `AGENTTEAMS_CONTROLLER_URL`, `AGENTTEAMS_AUTH_TOKEN`, `AGENTTEAMS_AUTH_TOKEN_FILE`, and `AGENTTEAMS_CLUSTER_ID` while preserving legacy `HICLAW_*` fallbacks, so Manager and Worker containers can use the terminal env names for controller calls.
- **Team Leader task routing guidance**: Leader project/task skills now describe Worker `assignedTo` values with a concise Matrix-localpart rule instead of long defensive warning blocks.
- **CoPaw worker runtime environment**: CoPaw workers now prefer AgentTeams storage/runtime environment variables while preserving legacy HiClaw fallbacks, and Qwen-style model health preflights disable thinking for lightweight readiness checks.
- **CoPaw Worker heartbeat**: CoPaw worker templates now seed heartbeat at a 10-minute interval so Team Leader agents created from the worker template can run heartbeat turns without requiring an explicit Team CR heartbeat spec.
- **Helm CRDs**: Removed unsupported `propertyNames` schema fields from Worker and Team CRDs so Kubernetes API servers accept the chart CRDs.
Expand Down
21 changes: 5 additions & 16 deletions manager/agent/team-leader-agent/skills/project-management/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,21 +151,10 @@ Each node uses:
- `assignedTo`
- `dependsOn`

For `assignedTo`, use the Worker's **Matrix localpart** (the part between `@` and `:` in `matrixUserID`). Extract it mechanically — never guess, strip, or transform.

**Lookup steps (mandatory before every `plan_dag` / `plan_loop` call):**
1. Run `hiclaw get workers --team "$TEAM_CR" -o json`
2. For each Worker, extract the localpart from `.matrixUserID`: e.g. `@worker-issue-resolver:domain` → `worker-issue-resolver`
3. Use that localpart verbatim as `assignedTo`

❌ Do NOT use CLI `.name` field directly (it may include deployment prefixes like `magic-cn-...-worker-issue-resolver`)
❌ Do NOT strip prefixes yourself — you will incorrectly remove legitimate name components
❌ Do NOT infer worker names from memory, AGENTS.md, or display names

| CLI `.name` | `matrixUserID` | ✅ `assignedTo` | ❌ Wrong |
|---|---|---|---|
| `magic-cn-x0a4t4pr201-worker-issue-resolver` | `@worker-issue-resolver:domain` | `worker-issue-resolver` | `issue-resolver` |
| `magic-cn-plt4s29va0r-worker-dev-worker` | `@dev-worker:domain` | `dev-worker` | `worker` |
For `assignedTo`, use the Worker's **Matrix localpart**: the part between
`@` and `:` in `matrixUserID`. Run `hiclaw get workers --team "$TEAM_CR" -o
json`, read each Worker's `matrixUserID`, and copy that localpart verbatim.
Example: `@worker-issue-resolver:domain` -> `worker-issue-resolver`.

Do not use `worker`, `owner`, `dependencies`, or standalone short IDs.

Expand Down Expand Up @@ -222,7 +211,7 @@ Optional inputs:
- `status`
- `tasks`

For every Loop task, `assignedTo` follows the same rule as DAG tasks: extract the Matrix localpart from `hiclaw get workers` output. Never strip or transform.
For every Loop task, `assignedTo` follows the same Matrix localpart rule as DAG tasks.

Use `ready_loop_nodes` to find pending nodes in the current iteration whose dependencies are satisfied by accepted `[x]` nodes. Delegate returned nodes with `task-management`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ Each task node uses:

- `taskId`: stable node ID. Use `{projectId}-{seq}`.
- `title`: short human-readable work unit.
- `assignedTo`: Worker's **Matrix localpart** (the part between `@` and `:` in `matrixUserID`). Extract mechanically from `hiclaw get workers --team "$TEAM_CR" -o json` output. Never strip, guess, or transform.
- ❌ Do NOT use CLI `.name` field directly (may include deployment prefixes)
- ❌ Do NOT strip prefixes yourself
- Example: `@worker-issue-resolver:domain` → `worker-issue-resolver`
- `assignedTo`: Worker's **Matrix localpart** (the part between `@` and `:` in `matrixUserID`). Get it from `hiclaw get workers --team "$TEAM_CR" -o json` and copy it verbatim. Example: `@worker-issue-resolver:domain` -> `worker-issue-resolver`.
- `dependsOn`: list of task IDs that must produce accepted upstream results first.

Do not use `worker`, `owner`, `dependencies`, or short standalone IDs like `st-01`.
Expand Down
29 changes: 6 additions & 23 deletions manager/agent/team-leader-agent/skills/task-management/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,36 +109,19 @@ Keep machine-facing identifiers and protocol tokens unchanged:

## Worker Name Canonicality

`assigned_to`, Matrix @mention, and all task tracking fields must use the Worker's **Matrix localpart** (the part between `@` and `:` in `matrixUserID`). Extract it mechanically — never guess, strip, or transform.
`assigned_to`, Matrix @mentions, and task tracking fields use the Worker's
**Matrix localpart**: the part between `@` and `:` in `matrixUserID`. Get team
workers with `hiclaw get workers --team "$TEAM_CR" -o json`, read
`matrixUserID`, and copy the localpart verbatim.

### Lookup (mandatory before assigning any task)
Example: `@worker-issue-resolver:domain` -> `worker-issue-resolver`.

```bash
# 1. Resolve team CR name
TEAM_CR="$(hiclaw get workers "${HICLAW_WORKER_CR_NAME:-$HICLAW_WORKER_NAME}" -o json | jq -r '.team')"

# 2. Get all team workers
hiclaw get workers --team "$TEAM_CR" -o json

# 3. Extract localpart from matrixUserID for each worker
# @worker-issue-resolver:domain → worker-issue-resolver
```

Use the extracted localpart verbatim everywhere:
Use that value everywhere:

- `manage-team-state.sh --assigned-to <localpart>`
- Matrix @mention: `@<localpart>:<domain>`
- `meta.json` `assigned_to` field

### Common mistake

CLI `.name` may include a deployment prefix (e.g. `magic-cn-x0a4t4pr201-worker-issue-resolver`). **Do NOT use `.name` directly and do NOT manually strip prefixes.** Always extract the localpart from `.matrixUserID` instead.

| CLI `.name` | `matrixUserID` | ✅ `assigned_to` | ❌ Wrong |
|---|---|---|---|
| `magic-cn-...-worker-issue-resolver` | `@worker-issue-resolver:domain` | `worker-issue-resolver` | `issue-resolver` |
| `magic-cn-...-dev-worker` | `@dev-worker:domain` | `dev-worker` | `worker` |

## Delegate A Ready Node

Delegate only nodes returned by:
Expand Down
58 changes: 18 additions & 40 deletions tests/test-06-multi-worker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,53 +35,31 @@ wait_for_manager_agent_ready 300 "${DM_ROOM}" "${ADMIN_TOKEN}" || {
exit 1
}

# test-05 can leave CoPaw Manager finishing heartbeat / pending-worker cleanup
# replies in the admin DM. Let that prior turn go quiet before measuring Bob's
# create-worker ack/provisioning SLA; the post-request waits below stay strict.
if ! matrix_wait_for_sender_quiet "${ADMIN_TOKEN}" "${DM_ROOM}" "@manager" 20 180; then
log_fail "Manager DM did not become quiet before Bob create request"
test_teardown "06-multi-worker"
test_summary
exit 1
fi

# Alice is running from previous tests; bob will be created below (offset=0 is correct for new workers)
wait_for_worker_container "alice" 60
METRICS_BASELINE=$(snapshot_baseline "alice" "bob")
TEST_WORKER_RUNTIME="${HICLAW_DEFAULT_WORKER_RUNTIME:-openclaw}"
# worker-management/SKILL.md tells Manager to ask admin for FOUR inputs
# (name / runtime / SOUL / skills) before running `hiclaw create worker`
# and not to invent defaults. A vague prompt that only names the worker is
# therefore a coin flip — sometimes Manager replies with a confirmation
# request, never calls the CLI, and the consumer/SOUL.md polls below
# silently time out. Spell out all four inputs and tell Manager to skip
# confirmation so this test exercises actual Worker creation.
#
# The runtime is explicit because the CI matrix runtime is the source of truth;
# rendered Manager workspace text may contain fallback defaults.
matrix_send_message "${ADMIN_TOKEN}" "${DM_ROOM}" \
"Please create a new Worker now using these exact values — do not ask me to confirm any of them:
- name: bob
- runtime: ${TEST_WORKER_RUNTIME} (use this exact runtime; do not reinterpret it as the install default)
- SOUL/role: Backend developer specializing in REST APIs, server-side logic, and data persistence
- skills: github-operations (file-sync / task-progress / project-participation are auto-included, no need to ask)

Proceed immediately and tell me when he is created."

log_info "Waiting for Manager to create Worker Bob..."
REPLY=$(matrix_wait_for_reply_matching "${ADMIN_TOKEN}" "${DM_ROOM}" "@manager" \
"bob.*(accepted|created|creating|pending|running|ready)" 300 \
"${ADMIN_TOKEN}" "${DM_ROOM}" "Please check if the request to create worker bob has been processed.")

assert_not_empty "${REPLY}" "Manager replied to create bob request"
assert_contains_i "${REPLY}" "bob" "Reply mentions worker name 'bob'"
# This test verifies multi-worker collaboration after Alice and Bob exist. Bob
# creation must be deterministic setup: asking the Manager to create him via DM
# is flaky under CI because the Manager may still be processing heartbeat/task
# follow-ups from earlier shard-A tests, or may hit a tool-guard prompt before
# calling `hiclaw create worker`. Use the controller CLI directly here so the
# collaboration assertions below measure the multi-worker flow, not LLM timing.
BOB_SOUL="Backend developer specializing in REST APIs, server-side logic, and data persistence"
log_info "Creating Worker Bob via hiclaw CLI (runtime: ${TEST_WORKER_RUNTIME})..."
CREATE_OUTPUT=$(exec_in_agent hiclaw apply worker --name bob \
--runtime "${TEST_WORKER_RUNTIME}" \
--soul "${BOB_SOUL}" \
--skills github-operations 2>&1)
if echo "${CREATE_OUTPUT}" | grep -qiE "worker/bob (created|configured)"; then
log_pass "hiclaw apply worker bob accepted"
else
log_fail "hiclaw apply worker bob failed: ${CREATE_OUTPUT}"
fi

# Verify Bob's infrastructure. Worker creation is asynchronous, so wait on
# persisted provisioning state and gateway side effects instead of sleeping.
BOB_PROVISION_TIMEOUT=60
if echo "${REPLY}" | grep -qiE "bob.*(accepted|creating|pending)" 2>/dev/null; then
BOB_PROVISION_TIMEOUT=180
fi
BOB_PROVISION_TIMEOUT=180
if wait_worker_provisioned "bob" "${BOB_PROVISION_TIMEOUT}"; then
log_pass "Worker Bob provisioned (roomID + matrixUserID populated)"
else
Expand Down
Loading