# Teamharness Project Management

> Use when a Leader maintains durable TeamHarness project state for Quick Task or Project Work: create_quick_project, create_project, plan_dag, plan_loop, ready_nodes, resolve_project, accept_task_result, project completion, and requester report state. Do not use to create Matrix task rooms or send messages.

- Skill: `agentscope-ai/teamharness-project-management` (Agent Skill)
- Install (CLI): `npx skillmds@latest add agentscope-ai/teamharness-project-management`
- Raw SKILL.md: https://api.skillmd.com/api/skills/agentscope-ai/teamharness-project-management/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: agentscope-ai (https://skillmd.com/u/agentscope-ai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/agentscope-ai/teamharness-project-management

---


# Project Management

Use this skill when maintaining durable project state.

A project owns the plan, context, dependencies, and accepted progress. Keep the
project plan separate from individual task execution logs.

Only advance a dependency after the Leader accepts the submitted result.
Do not use this skill for ordinary direct replies or lightweight one-off
actions.

## Scope

Use this skill when acting as Leader for:

- `projectflow` calls
- project creation
- quick single-task project creation
- DAG planning
- Loop planning
- ready-node resolution
- Loop iteration recording
- accepting checked Worker results into project progress
- project-level status reports

For Project Work, use `teamharness-team-coordination` first to decide task
boundaries. If no task room exists yet, use `teamharness-roomflow` and
`teamharness-communication` before this skill. Use
`teamharness-task-delegation` for individual task specs, assignment messages,
and Worker result checks.

## Project Files

Project files live under:

```text
shared/projects/{project-id}/
```

TeamHarness writes CoPaw-compatible task runtime files:

```text
shared/projects/{project-id}/meta.json
shared/projects/{project-id}/plan.md
```

Write a final project result, when needed, to:

```text
shared/projects/{project-id}/result.md
```

The Leader owns this project result file. Build it from accepted project state
and accepted task deliverables; do not ask Workers to write or submit it as a
task deliverable.

Use `projectflow` to change `meta.json` and `plan.md`; do not hand-edit
project state unless a tool failure leaves no safe alternative.

## ID Rules

Use safe IDs only:

```text
[A-Za-z0-9][A-Za-z0-9._-]*
```

Do not use colons, slashes, spaces, or Matrix IDs as project or task IDs.

Suggested formats:

```text
projectId: {short-description}-YYYYMMDD-HHMMSS
taskId: {projectId}-{seq}
```

If a user or test provides explicit IDs, preserve them when they are already
safe.

## Tool Payload Rule

When calling `projectflow`, pass `payload` as a JSON object, not as a serialized
JSON string.

## Create Project

Create the project before planning tasks:

```json
{
  "action": "create_project",
  "payload": {
    "projectId": "demo-project-001",
    "title": "Demo Project",
    "source": "dingtalk",
    "requester": "dingtalk:sender_001:aaaaaaaa",
    "replyRoute": {
      "channel": "dingtalk",
      "targetUser": "sender_001",
      "targetSession": "aaaaaaaa"
    }
  }
}
```

This creates `meta.json` and `plan.md`.

`team_id` is stamped automatically from the runtime team configuration; pass
`payload.teamId` explicitly only when the project must belong to a different
team than the calling Worker's own team.

If `projectId` is omitted, TeamHarness derives one from `title` plus timestamp.
If the generated ID already exists, TeamHarness appends a numeric suffix.
Explicit `projectId` collisions are rejected.

Use `replyRoute` when the requester came from a runtime channel that may need a
cross-session final report. `channel`, `targetUser`, and `targetSession` must
come from the current message/session metadata or a trusted runtime query. Do
not guess them.

For Project Work that should proceed in a dedicated task room, do not call
`create_project` in the requester/source session. Use
`teamharness-communication` to send a `PROJECT_REQUESTED` self-trigger from the
current requester/source session to the same Leader in the target Matrix task
room first. After the task-room Leader session wakes up, call `create_project`
there and preserve the original requester route from the visible
`PROJECT_REQUESTED` request: keep the original `source`, `requester`,
`sourceRoomId`, and `replyRoute` so final reports can return to the
DingTalk group, Matrix DM, or other source room that made the request. Do not
invent missing `replyRoute` values from requester names or prose.

For DingTalk requester compatibility, `requester` may use
`dingtalk:{user_id}:{session_id}`; TeamHarness derives `reply_route` from that
value when `replyRoute` is not provided.

## Create Quick Project

Use `create_quick_project` only after Quick Task mode is selected and the
Leader is in the Matrix Task room that received the task request message. It is
a shortcut for:

```text
create_project + plan single-node DAG + assigned task spec
```

Do not call this in the requester/source session. If the current session is
still a DingTalk group, Matrix DM, Team room, or other source room, return to
`TEAMS.md`: create or reuse the task room with `teamharness-roomflow`, hand the
request to that room with `teamharness-communication`, and stop in the source
session.

Before calling this action in the Task room:

1. Use the current Matrix task room as `roomId`.
2. Preserve the original `source`, `requester`, `sourceRoomId`, and `replyRoute`
   from the task request message. Do not guess route values.
3. Choose the one Worker owner from the team roster.
4. Write a bounded task spec that includes the completion report instruction
   from `teamharness-task-delegation`.

`teamharness-roomflow` owns task-room creation, project-scoped reuse, source
metadata capture, and Worker invites. This skill only creates durable project
and task state after the Task room is already selected.

Example:

```json
{
  "action": "create_quick_project",
  "payload": {
    "title": "Write readiness note",
    "source": "matrix",
    "requester": "@admin:matrix.local",
    "sourceRoomId": "!admin-dm:matrix.local",
    "assignedTo": "@worker-a:matrix.local",
    "roomId": "!task-room:matrix.local",
    "spec": "# Task\n\nWrite one concise readiness note.",
    "replyRoute": {
      "channel": "matrix",
      "targetUser": "@admin:matrix.local",
      "targetSession": "!admin-dm:matrix.local"
    }
  }
}
```

This writes:

```text
shared/projects/{projectId}/meta.json
shared/projects/{projectId}/plan.md
shared/tasks/{taskId}/meta.json
shared/tasks/{taskId}/spec.md
```

It sets `mode: quick`, `plan_type: dag`, and the single task status to
`assigned`. It does not send the Matrix or external-channel assignment message;
send that message only after the tool returns `ok: true`.

## Plan DAG

Use DAG when the work is finite and dependencies are known enough to plan now.

Call `plan_dag` with the complete graph you want to keep:

```json
{
  "action": "plan_dag",
  "payload": {
    "projectId": "demo-project-001",
    "tasks": [
      {
        "taskId": "demo-project-001-01",
        "title": "Implement the worker-owned part",
        "assignedTo": "@worker-a:matrix.local",
        "dependsOn": []
      }
    ]
  }
}
```

For `assignedTo`, use the Worker Matrix ID or the stable runtime/member name
from `TEAMS.md`. Do not invent a Worker name.

`plan_dag` returns `readyNodes`. Delegate only ready nodes.

## Ready Nodes

Use `ready_nodes` when you need the next pending or assigned DAG nodes whose
dependencies are completed:

```json
{
  "action": "ready_nodes",
  "payload": {
    "projectId": "demo-project-001"
  }
}
```

Only nodes with dependencies marked `completed` unblock downstream work.

## Plan Loop

Use Loop when `teamharness-team-coordination` decided the work should repeat
until a stop condition, quality gate, evidence threshold, or maximum iteration
count.

Call `plan_loop` with the complete current-iteration plan you want to keep:

```json
{
  "action": "plan_loop",
  "payload": {
    "projectId": "demo-project-001",
    "goal": "Improve the result until tests pass",
    "stopCondition": "All target tests pass or maxIterations is reached",
    "iterationTemplate": "Inspect result, choose one bounded fix, run tests.",
    "maxIterations": 3,
    "currentIteration": 1,
    "tasks": [
      {
        "taskId": "demo-project-001-i001-01",
        "title": "Run iteration 1",
        "assignedTo": "@worker-a:matrix.local",
        "dependsOn": []
      }
    ]
  }
}
```

Required Loop inputs:

- `goal`
- `stopCondition`
- `iterationTemplate`
- `maxIterations`

Use `ready_loop_nodes` to find pending nodes in the current iteration whose
dependencies are completed:

```json
{
  "action": "ready_loop_nodes",
  "payload": {
    "projectId": "demo-project-001"
  }
}
```

After evaluating an iteration, use `record_loop_iteration`:

```json
{
  "action": "record_loop_iteration",
  "payload": {
    "projectId": "demo-project-001",
    "iteration": 1,
    "decision": "continue",
    "summary": "One target still fails.",
    "nextAction": "Plan the next fix pass."
  }
}
```

Allowed decisions are `continue`, `replan`, `ask_user`, `stop_success`, and
`stop_blocked`.

Do not pre-expand repeated Loop rounds into a large DAG. Plan the current
iteration, evaluate it, record the iteration decision, then decide whether to
continue, replan, ask the requester, stop successfully, or stop blocked.

## Resolve Project Context

When a Worker completion or blocker wakes the Leader in a fresh session, do not
guess the project from the current room. First resolve the context from the task
id:

```json
{
  "action": "resolve_project",
  "payload": {
    "taskId": "demo-project-001-01"
  }
}
```

`resolve_project` returns the ProjectMeta, TaskMeta, `replyRoute`, plan type, and
ready nodes that the Leader needs to resume normal project flow.

## Accepting Worker Results

A Worker `SUCCESS` or `SUCCESS_WITH_NOTES` result is only a candidate result.
After `teamharness-task-delegation` checks the task and returns `effective:
true`, decide whether to accept the result.

To accept a result, call `accept_task_result`:

```json
{
  "action": "accept_task_result",
  "payload": {
    "projectId": "demo-project-001",
    "taskId": "demo-project-001-01",
    "resultStatus": "SUCCESS",
    "summary": "Completed the assigned work."
  }
}
```

`accept_task_result` updates the DAG or Loop node and records
`requester_report.pending` in ProjectMeta. Keep unresolved nodes in their current
state.

Accepting a completed result does not publish the project artifact by default.
Write or update `shared/projects/{project-id}/result.md` as the Leader when a
project-level report file is needed. After the requester report message is sent
to a Matrix requester room, publish `shared/projects/{project-id}/result.md`
with `artifact publish_file` and set `parentEventId` to the report message id.
Use `publishArtifacts: true` only when you intentionally want an immediate
project artifact before the requester report.

Then call `ready_nodes` and delegate any newly ready downstream node with
`teamharness-task-delegation`.

After the project state changes, close the loop with requester visibility:

1. Read `shared/projects/{project-id}/meta.json` and `plan.md`.
2. Build the requester-facing content with the Project Status Reports template
   below.
3. Use `teamharness-communication`
   `## Requester Report Delivery Protocol` to deliver the report to the
   requester recorded on the project.
4. If the requester report was sent to a Matrix room and
   `shared/projects/{project-id}/result.md` exists, call `artifact publish_file`
   for that file with `parentEventId` set to the report message id.
5. If the requester report was sent to DingTalk, Feishu, WeChat, or another
   non-Matrix channel, do not claim that a file was attached or published in
   that channel. In the report text, list the important `shared/...` artifact
   paths and say they are available from the shared workspace or platform
   object-storage view.
6. After successful delivery, call `mark_requester_report_sent`.

Task room coordination, Worker completion messages, downstream assignment
messages, and tool-call summaries do not count as the requester report. You may
batch several accepted task results and downstream delegations into one
requester report, but do not omit the report when accepted project state
changed.

## Project Status Reports

Build status report content here because this skill owns project execution
state. Use `teamharness-communication` only for destination selection, message
tool payloads, Matrix message formatting, and same-room versus cross-room
delivery.

Before writing a requester report:

1. Read `shared/projects/{project-id}/meta.json` and `plan.md`.
2. Identify the plan type from `meta.json` or `plan.md`.
3. For DAG, report dependency progress and the next ready nodes.
4. For Loop, report current iteration progress, the latest decision, and the
   next iteration path.
5. Write the report in the requester's language, then use
   `teamharness-communication` to deliver it to the requester recorded on the
   project.

Use stable state markers and localize the visible labels:

| State | Marker |
|---|---|
| Completed | `[done]` |
| In Progress | `[active]` |
| Pending | `[pending]` |
| Blocked | `[blocked]` |
| Revision | `[revision]` |

Keep the report envelope consistent across DAG and Loop:

````markdown
---

## <localized project status report heading>

**<localized project name label>**: <name>
**<localized project ID label>**: <project-id>
**<localized execution mode label>**: <DAG or Loop>
**<localized project status label>**: <marker + localized state label>
**<localized current focus label>**: <DAG wave/current node, or Loop iteration n / max and topic>

**<localized summary label>**: <1-3 sentences about what changed and what happens next>

**<localized task status label>**:
| <localized task ID label> | <localized task title label> | <localized owner label> | <localized status label> | <localized context label> |
|---|---|---|---|---|
| <task-id> | <title> | <worker> | <marker + localized state label> | <dependencies, iteration role, result note, or -> |

**<localized execution progress label>**:
```text
<DAG dependency flow or Loop iteration line; choose the matching shape below>
```

**<localized deliverables label>**:
- `<path>` - <what it contains>

For Matrix requester reports, this section may say the report file or artifact
was published to the requester room only after `artifact publish_file` succeeds.
For DingTalk, Feishu, WeChat, or other non-Matrix requester reports, say the
files are available from the shared workspace or platform object-storage view;
do not say "attached", "uploaded to this chat", "click the file card", or
"view the file here".

**<localized next steps label>**:
1. <next DAG transition, next Loop decision, or requester action>

**<localized notes label>**: <blocker, risk, or decision needed; omit section if none>
````

In requester-facing reports, owner or executor cells are descriptive text.
Use plain Worker display names or role names such as `workeraa`, `workerbb`, or
`WorkerAA`. Do not prefix them with `@`, do not use full Matrix user ids, and do
not create Matrix mention links unless the report is intentionally asking that
member to respond or take action.

Use this execution progress shape for DAG reports:

```text
<task-id> [done] -> <task-id> [active] -> <task-id> [pending]
                                  ^
<task-id> [done] -----------------|
```

Use the DAG progress section to show the dependency path that changed, newly
unblocked nodes, or the next ready wave. If the graph is large, show only the
relevant changed path and summarize the rest in the task table.

Use this execution progress shape for Loop reports:

```text
Iteration 1 [done] -> Iteration 2 [active] -> Iteration 3 [pending] ... Max <n>
                       Current: <current iteration topic>
                       Decision: <continue, replan, ask_user, stop_success, stop_blocked, or pending evaluation>
```

Use the Loop progress section to show current iteration number, maximum
iterations, current iteration topic, and the latest Leader decision. Do not
present future Loop rounds as if they were pre-planned DAG tasks. Show only the
current iteration's task statuses in the task table unless prior iteration
context is necessary.

For intermediate updates, include the Project header, summary, task status
table, and next steps. Omit the deliverables section unless new deliverables
are available, and omit the execution progress section only when neither DAG
flow nor Loop iteration state changed.

After the requester report is sent, clear the pending flag:

```json
{
  "action": "mark_requester_report_sent",
  "payload": {
    "projectId": "demo-project-001"
  }
}
```

## Post-Action Notification

State-mutating `projectflow` and `taskflow` operations return a
`notificationNeeded` field when they succeed. This field is a hint — the tool
does not send any message automatically. The Leader must act on it.

When `notificationNeeded` is present in the tool result:

1. Check `notificationNeeded.targetRoom`. If it matches the current session
   room, a direct reply in the current session is sufficient — no cross-room
   message is needed.
2. If `targetRoom` is a different room, use the `message` tool to send a brief
   status update to that room. Use `m.notice`-style concise format:
   `[ProjectFlow] {event}: {summary}`.
3. If `notificationNeeded.replyRoute` is present and the event is
   `accept_task_result` or `complete_project`, this is the requester report
   trigger — follow the Requester Report Delivery Protocol in
   `teamharness-communication`.
4. Do not send a notification if the tool returned `ok: false`.
5. Do not send duplicate notifications for the same event within a single
   Leader turn — one notification per state change is sufficient.

The `notificationNeeded` field contains:

```json
{
  "event": "create_project",
  "projectId": "demo-project-001",
  "summary": "create_project: Demo Project",
  "targetRoom": "!task-room:matrix.local",
  "replyRoute": { "channel": "matrix", "targetSession": "..." }
}
```

`targetRoom` and `replyRoute` may be absent when no room context is available
(for example, a bare `create_project` before any task room exists). In that
case, skip the notification — the assignment message or requester report will
carry the project context later.

## Pause / Resume / Complete

Use these when a human asks the Leader to pause, resume, or complete a
project (or when the Leader decides a project should stop dispatching new
work). A Controller API also implements these as structured endpoints; this
skill documents the MCP-native path a Leader uses in conversation.

Call `pause_project` to stop new task dispatch. In-flight tasks are NOT
cancelled — they keep running and their completion reports still arrive. Do
not delegate new ready nodes while paused.

```json
{
  "action": "pause_project",
  "payload": {
    "projectId": "demo-project-001"
  }
}
```

Call `resume_project` to put a paused project back to `active`:

```json
{
  "action": "resume_project",
  "payload": {
    "projectId": "demo-project-001"
  }
}
```

Call `complete_project` only when every task has reached a terminal status
(completed / revision / blocked / cancelled) and no work remains — a
completed project is terminal. Pass `publishArtifacts: true` only when you
intentionally want an immediate project artifact before the requester report
(see Accepting Worker Results):

```json
{
  "action": "complete_project",
  "payload": {
    "projectId": "demo-project-001",
    "publishArtifacts": false
  }
}
```

`pause_project` / `resume_project` / `complete_project` change project status
only; they do not cancel in-flight tasks or delete task state. If a task must
be cancelled, use `taskflow cancel_task` (Leader only) with a reason.

## Current Boundary

TeamHarness v0.1 supports project creation, quick single-task project creation,
project context resolution, DAG planning, DAG ready-node resolution, Loop
planning, Loop ready-node resolution, Loop iteration recording, explicit result
acceptance, requester report clearing, `pause_project`, `resume_project`, and
`complete_project`. DAG and Loop task plans reject duplicate task ids, unknown
dependencies, and dependency cycles. Do not call unsupported `projectflow`
actions.

