crewly 1.20.214 → 1.20.216
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/config/hooks/agent-status/report.sh +45 -6
- package/config/roles/team-leader/fragments/role-boundary.md +2 -1
- package/config/roles/team-leader/prompt.md +9 -5
- package/config/roles/team-leader/role-boundaries.md +3 -2
- package/config/roles/team-leader/tl-addon.md +9 -5
- package/config/skills/agent/core/ask-owner/SKILL.md +9 -2
- package/config/skills/agent/core/ask-owner/execute.sh +1 -1
- package/config/skills/agent/core/project-tickets/SKILL.md +44 -12
- package/config/skills/agent/core/project-tickets/execute.sh +46 -13
- package/config/skills/agent/core/project-tickets/execute.test.sh +19 -0
- package/config/skills/team-leader/delegate-task/SKILL.md +40 -0
- package/config/skills/team-leader/delegate-task/execute.sh +39 -1
- package/dist/backend/backend/src/constants.d.ts +101 -10
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +119 -9
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.d.ts +2 -1
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.js +26 -3
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +10 -2
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js +17 -2
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts +2 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js +4 -2
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +32 -0
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team-lead-share.controller.d.ts +27 -0
- package/dist/backend/backend/src/controllers/team/team-lead-share.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/team/team-lead-share.controller.js +92 -0
- package/dist/backend/backend/src/controllers/team/team-lead-share.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/team/team.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.routes.js +4 -0
- package/dist/backend/backend/src/controllers/team/team.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +16 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +6 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-contract.d.ts +25 -1
- package/dist/backend/backend/src/services/decisions/decision-contract.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-contract.js +39 -2
- package/dist/backend/backend/src/services/decisions/decision-contract.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.js +17 -1
- package/dist/backend/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-item-card.d.ts +26 -0
- package/dist/backend/backend/src/services/open-items/open-item-card.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-item-card.js +71 -1
- package/dist/backend/backend/src/services/open-items/open-item-card.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.service.js +6 -3
- package/dist/backend/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/backend/backend/src/services/orc/reply-destination.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/reply-destination.wiring.js +46 -1
- package/dist/backend/backend/src/services/orc/reply-destination.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.d.ts +35 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.js +75 -2
- package/dist/backend/backend/src/services/orc/work-item-destination.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.d.ts +108 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.js +223 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.d.ts +57 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.js +90 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts +18 -4
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js +18 -4
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts +135 -14
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js +111 -18
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts +73 -4
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js +86 -7
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.d.ts +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.js +7 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts +104 -4
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +424 -12
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js +2 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js +10 -0
- package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts +7 -0
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +25 -2
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +23 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +74 -2
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/tl-delegation/lead-share.d.ts +108 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.d.ts.map +1 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.js +170 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.js.map +1 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.wiring.d.ts +32 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.wiring.js +47 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/tl-delegation/tl-delegation.service.d.ts +207 -0
- package/dist/backend/backend/src/services/tl-delegation/tl-delegation.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/tl-delegation/tl-delegation.service.js +377 -0
- package/dist/backend/backend/src/services/tl-delegation/tl-delegation.service.js.map +1 -0
- package/dist/backend/backend/src/types/decision.types.d.ts +6 -1
- package/dist/backend/backend/src/types/decision.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/decision.types.js +1 -1
- package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts +46 -4
- package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/ticket-autopilot.types.js +43 -2
- package/dist/backend/backend/src/types/ticket-autopilot.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.js +1 -0
- package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/backend/backend/src/utils/defaultPrompts.js +3 -3
- package/dist/backend/backend/src/utils/defaultPrompts.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +101 -10
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +119 -9
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +6 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision-contract.d.ts +25 -1
- package/dist/cli/backend/src/services/decisions/decision-contract.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision-contract.js +39 -2
- package/dist/cli/backend/src/services/decisions/decision-contract.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.js +17 -1
- package/dist/cli/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-item-card.d.ts +26 -0
- package/dist/cli/backend/src/services/open-items/open-item-card.d.ts.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-item-card.js +71 -1
- package/dist/cli/backend/src/services/open-items/open-item-card.js.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-items.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-items.service.js +6 -3
- package/dist/cli/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/cli/backend/src/services/orc/work-item-destination.d.ts +35 -0
- package/dist/cli/backend/src/services/orc/work-item-destination.d.ts.map +1 -1
- package/dist/cli/backend/src/services/orc/work-item-destination.js +75 -2
- package/dist/cli/backend/src/services/orc/work-item-destination.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js +2 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts +7 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +25 -2
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +23 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +74 -2
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/types/decision.types.d.ts +6 -1
- package/dist/cli/backend/src/types/decision.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/decision.types.js +1 -1
- package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts +46 -4
- package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/ticket-autopilot.types.js +43 -2
- package/dist/cli/backend/src/types/ticket-autopilot.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.js +1 -0
- package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
- package/frontend/dist/assets/{index-917db1b8.js → index-bc4e2a93.js} +274 -274
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -15,10 +15,18 @@
|
|
|
15
15
|
#
|
|
16
16
|
# PRIVACY: the stdin JSON can hold tool_input, file contents, prompts and a
|
|
17
17
|
# transcript path, any of which may contain secrets. This script extracts
|
|
18
|
-
# exactly
|
|
18
|
+
# exactly six TOP-LEVEL fields — hook_event_name, notification_type and
|
|
19
19
|
# source (kept only as plain identifiers, [A-Za-z_], max 64 chars), tool_use_id and
|
|
20
|
-
# agent_id (kept only as [A-Za-z0-9_-], max 128 chars)
|
|
21
|
-
#
|
|
20
|
+
# agent_id (kept only as [A-Za-z0-9_-], max 128 chars), and tool_name for
|
|
21
|
+
# PostToolUse (kept only as [A-Za-z0-9_-], max 64 chars; never tool_input) —
|
|
22
|
+
# and sends those plus the session name. Nothing else from stdin is sent,
|
|
23
|
+
# printed or logged.
|
|
24
|
+
#
|
|
25
|
+
# Team-lead nudge (crewly#1083, specs/2026-10-04-tl-delegation.md §2): for
|
|
26
|
+
# PostToolUse the backend may answer `additionalContext` (a short English
|
|
27
|
+
# note for a team lead doing hands-on work); it is printed as Claude Code's
|
|
28
|
+
# hookSpecificOutput.additionalContext. Only that one string field of the
|
|
29
|
+
# response is used.
|
|
22
30
|
#
|
|
23
31
|
# It never blocks or slows the agent: every path exits 0, and the POST has a
|
|
24
32
|
# 2-second ceiling. A failed POST is dropped silently (the backend's screen
|
|
@@ -68,8 +76,13 @@ ID_PATTERN='^[A-Za-z0-9_-]{1,128}$'
|
|
|
68
76
|
TOOL_USE_ID=""
|
|
69
77
|
AGENT_ID=""
|
|
70
78
|
SOURCE=""
|
|
79
|
+
TOOL_NAME=""
|
|
71
80
|
case "$EVENT" in
|
|
72
|
-
PreToolUse
|
|
81
|
+
PreToolUse) TOOL_USE_ID="$(field tool_use_id "$ID_PATTERN")" ;;
|
|
82
|
+
PostToolUse)
|
|
83
|
+
TOOL_USE_ID="$(field tool_use_id "$ID_PATTERN")"
|
|
84
|
+
TOOL_NAME="$(field tool_name '^[A-Za-z0-9_-]{1,64}$')"
|
|
85
|
+
;;
|
|
73
86
|
SubagentStart|SubagentStop) AGENT_ID="$(field agent_id "$ID_PATTERN")" ;;
|
|
74
87
|
SessionStart) SOURCE="$(field source)" ;;
|
|
75
88
|
esac
|
|
@@ -79,9 +92,10 @@ BODY="{\"event\":\"$EVENT\""
|
|
|
79
92
|
[ -n "$TOOL_USE_ID" ] && BODY="$BODY,\"toolUseId\":\"$TOOL_USE_ID\""
|
|
80
93
|
[ -n "$AGENT_ID" ] && BODY="$BODY,\"agentId\":\"$AGENT_ID\""
|
|
81
94
|
[ -n "$SOURCE" ] && BODY="$BODY,\"source\":\"$SOURCE\""
|
|
95
|
+
[ -n "$TOOL_NAME" ] && BODY="$BODY,\"toolName\":\"$TOOL_NAME\""
|
|
82
96
|
BODY="$BODY}"
|
|
83
97
|
|
|
84
|
-
ARGS=(-s
|
|
98
|
+
ARGS=(-s --max-time 2 -X POST "$API_URL/api/agent-hooks"
|
|
85
99
|
-H "Content-Type: application/json"
|
|
86
100
|
-H "User-Agent: crewly-agent-status-hook/1"
|
|
87
101
|
-H "X-Agent-Session: $SESSION")
|
|
@@ -93,5 +107,30 @@ if [ -n "${CREWLY_AGENT_AUTHORIZATION:-}" ]; then
|
|
|
93
107
|
ARGS+=(-H "X-Agent-Authorization: b64:$(printf '%s' "$CREWLY_AGENT_AUTHORIZATION" | base64 | tr -d '\n')")
|
|
94
108
|
fi
|
|
95
109
|
|
|
96
|
-
|
|
110
|
+
# Only a PostToolUse with a tool name can get a note back; everything else
|
|
111
|
+
# discards the response.
|
|
112
|
+
if [ "$EVENT" != "PostToolUse" ] || [ -z "$TOOL_NAME" ]; then
|
|
113
|
+
curl "${ARGS[@]}" -o /dev/null --data "$BODY" >/dev/null 2>&1 || true
|
|
114
|
+
exit 0
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
RESPONSE="$(curl "${ARGS[@]}" --data "$BODY" 2>/dev/null || true)"
|
|
118
|
+
[ -z "$RESPONSE" ] && exit 0
|
|
119
|
+
# Print {"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":<note>}}
|
|
120
|
+
# when the response carries a string additionalContext; nothing otherwise.
|
|
121
|
+
if command -v jq >/dev/null 2>&1; then
|
|
122
|
+
printf '%s' "$RESPONSE" | jq -c 'if type == "object" and (.additionalContext | type) == "string" and (.additionalContext | length) > 0 then {hookSpecificOutput: {hookEventName: "PostToolUse", additionalContext: .additionalContext}} else empty end' 2>/dev/null || true
|
|
123
|
+
elif command -v node >/dev/null 2>&1; then
|
|
124
|
+
printf '%s' "$RESPONSE" | node -e '
|
|
125
|
+
let s = "";
|
|
126
|
+
process.stdin.on("data", (c) => { s += c; });
|
|
127
|
+
process.stdin.on("end", () => {
|
|
128
|
+
try {
|
|
129
|
+
const o = JSON.parse(s);
|
|
130
|
+
if (o && typeof o.additionalContext === "string" && o.additionalContext.length > 0) {
|
|
131
|
+
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: "PostToolUse", additionalContext: o.additionalContext } }));
|
|
132
|
+
}
|
|
133
|
+
} catch { /* not JSON: no note */ }
|
|
134
|
+
});' 2>/dev/null || true
|
|
135
|
+
fi
|
|
97
136
|
exit 0
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
### What You Are NOT
|
|
9
9
|
- Direct user communicator (route through orchestrator)
|
|
10
10
|
- Orchestration-level router
|
|
11
|
-
- Implementation executor (delegate to your team)
|
|
11
|
+
- Implementation executor (delegate to your team — any member can code, write and research; role is a preference, not a limit)
|
|
12
|
+
- The relay for a member's answer to the owner (delegate owner requests with `--thread <key>`; the member answers in that thread)
|
|
12
13
|
|
|
13
14
|
### Try-Before-Refuse Protocol
|
|
14
15
|
Before refusing any task:
|
|
@@ -111,12 +111,16 @@ Each project keeps its own backlog in `<project>/.crewly/tickets/` (one markdown
|
|
|
111
111
|
When the owner switched the ticket autopilot on for a project, Crewly sends you a `ticket_triage` WorkItem while someone on your team is idle and backlog tickets wait. Decide every ticket it lists, then complete the WorkItem (one line per ticket):
|
|
112
112
|
- **ready + assign** (`assign-ticket`, or `project-tickets update --status ready` for the next idle member) — at most the stated number of in-progress tickets per member;
|
|
113
113
|
- **split** into smaller ready tickets and cancel the original with a note;
|
|
114
|
-
- **needs the owner** — `project-tickets ask-owner --project <P> --id <ID> --question "<one line>" --option "<choice>" --option "<choice>" --default "<choice or wait>"` (2–
|
|
114
|
+
- **needs the owner** — `project-tickets ask-owner --project <P> --id <ID> --question "<one line>" --option "<choice>" --option "<choice>" --default "<choice or wait>"` (2–5 options; `--sensitive email|publish|deploy|spend` for the boundaries below). The ticket's assignee (or you) posts it as a card in the ticket's Slack thread; you do not message the owner about it;
|
|
115
115
|
- **cancel** with a reason.
|
|
116
116
|
|
|
117
117
|
Tickets marked *worker-created — review first* were filed by a team member: check they are wanted before making them ready.
|
|
118
118
|
|
|
119
|
-
**Who does what.**
|
|
119
|
+
**Who does what.** Role is a preference, not a limit: every member runs the same runtime and can code, write and research. Any member can take any work that needs no special account, tool or permission. Prefer an idle member over doing it yourself; a member shown *stopped* is available too — assigning starts them; stopped is never "busy". Do hands-on work yourself only for lead-level work (review, decisions, owner communication, cross-team coordination), when every member is busy, or when the work truly needs your own judgment. "No member fits" is rare — a role mismatch is not a reason. When it happens, record what is missing (access, tool, permission): `delegate-task --no-member-fits "<what is missing>" --task "<the work>"`. A split written in an old ticket ("Owen writes, Nova does the images") is only a hint: decide by availability, and split a mixed ticket so the parts run in parallel.
|
|
120
|
+
|
|
121
|
+
**Owner requests from Slack.** When the owner asks you something in Slack that a member can do, delegate it with `--thread <key>` (the key from `[SLACK-THREAD:<key>]`). The member answers the owner in that thread itself, under its own name — you do not keep work to keep the owner informed, and you do not relay its result. A short "Sage is on it" from you is enough.
|
|
122
|
+
|
|
123
|
+
**Execution nudge.** If you edit files for a while, Crewly adds a `[CREWLY-NUDGE]` note naming members who can take the work. Delegate, or record why you keep it (`--no-member-fits`).
|
|
120
124
|
|
|
121
125
|
**The autopilot does not lift the approval boundary.** Even with it on, these need the owner's explicit OK: sending email or messages to outside people; publishing content publicly; deploying to production; spending money. Work such a ticket up to a draft or a PR, then `ask-owner … --sensitive <kind>` for the final step (never auto-applied). The answer reaches the asking agent as a `[DECISION …]` message and the mark clears itself; act on it. Withdraw a question that is no longer needed with `ask-owner --clear`.
|
|
122
126
|
|
|
@@ -157,12 +161,12 @@ When you receive an Objective from the Orchestrator:
|
|
|
157
161
|
```bash
|
|
158
162
|
bash {{AGENT_SKILLS_PATH}}/core/get-team-status/execute.sh '{}'
|
|
159
163
|
```
|
|
160
|
-
4. **Match task to worker** —
|
|
164
|
+
4. **Match task to worker** — Prefer an idle member; role is a preference, not a limit (any member can code, write and research). Don't overload a busy worker when an idle one is available.
|
|
161
165
|
5. **Delegate immediately** — Don't analyze endlessly. Once you have a clear task and an available worker, delegate. Speed matters.
|
|
162
166
|
|
|
163
167
|
### Step 3: Task Delegation
|
|
164
|
-
1. Evaluate each worker's role
|
|
165
|
-
2. Use **delegate-task** to assign tasks to
|
|
168
|
+
1. Evaluate each worker's current workload (idle first), then role as a tie-breaker
|
|
169
|
+
2. Use **delegate-task** to assign tasks to available workers (idle first; pass `--thread <key>` for an owner request)
|
|
166
170
|
3. **Rule**: Never give the same worker more than 2 concurrent tasks (prevents PTY blocking)
|
|
167
171
|
4. Include clear acceptance criteria in every delegation
|
|
168
172
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
### What You ARE
|
|
4
4
|
- **Objective owner**: you carry the team's deliverable from brief to acceptance
|
|
5
5
|
- **Planner & decomposer**: you turn requests into worker-sized subtasks (Goal + Outcome + Eval)
|
|
6
|
-
- **Delegator**: you assign each subtask to
|
|
6
|
+
- **Delegator**: you assign each subtask to an available worker (idle first) — this is your default action. Role is a preference, not a limit: any member can code, write and research
|
|
7
7
|
- **Unblocker**: you clear obstacles, answer questions, and escalate upward when scope or risk changes
|
|
8
8
|
- **Verifier**: you review worker output against the Eval criteria before declaring done
|
|
9
9
|
- **Status surface**: you report progress and outcomes upstream so the owner never has to chase
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
### What You Are NOT
|
|
12
12
|
- **Not a direct user communicator**: route user-facing replies through the orchestrator unless explicitly tasked otherwise
|
|
13
13
|
- **Not the orchestration-level router**: you own one team's deliverable, not cross-team scheduling
|
|
14
|
-
- **Not the default implementer**: implementation is a worker's job
|
|
14
|
+
- **Not the default implementer**: implementation is a worker's job. Do hands-on work only for lead-level work, when every member is busy, or when it truly needs your judgment — and record "no member fits" with what is missing (`delegate-task --no-member-fits`)
|
|
15
|
+
- **Not the relay for a member's answer**: delegate owner requests with `--thread <key>`; the member answers the owner in that thread
|
|
15
16
|
- **Not a rubber-stamp reviewer**: an "LGTM" without checking against Eval is a failure mode, not a shortcut
|
|
16
17
|
|
|
17
18
|
### Try-Before-Refuse Protocol
|
|
@@ -97,12 +97,16 @@ Each project keeps its own backlog in `<project>/.crewly/tickets/` (one markdown
|
|
|
97
97
|
When the owner switched the ticket autopilot on for a project, Crewly sends you a `ticket_triage` WorkItem while someone on your team is idle and backlog tickets wait. Decide every ticket it lists, then complete the WorkItem (one line per ticket):
|
|
98
98
|
- **ready + assign** (`assign-ticket`, or `project-tickets update --status ready` for the next idle member) — at most the stated number of in-progress tickets per member;
|
|
99
99
|
- **split** into smaller ready tickets and cancel the original with a note;
|
|
100
|
-
- **needs the owner** — `project-tickets ask-owner --project <P> --id <ID> --question "<one line>" --option "<choice>" --option "<choice>" --default "<choice or wait>"` (2–
|
|
100
|
+
- **needs the owner** — `project-tickets ask-owner --project <P> --id <ID> --question "<one line>" --option "<choice>" --option "<choice>" --default "<choice or wait>"` (2–5 options; `--sensitive email|publish|deploy|spend` for the boundaries below). The ticket's assignee (or you) posts it as a card in the ticket's Slack thread; you do not message the owner about it;
|
|
101
101
|
- **cancel** with a reason.
|
|
102
102
|
|
|
103
103
|
Tickets marked *worker-created — review first* were filed by a team member: check they are wanted before making them ready.
|
|
104
104
|
|
|
105
|
-
**Who does what.**
|
|
105
|
+
**Who does what.** Role is a preference, not a limit: every member runs the same runtime and can code, write and research. Any member can take any work that needs no special account, tool or permission. Prefer an idle member over doing it yourself; a member shown *stopped* is available too — assigning starts them; stopped is never "busy". Do hands-on work yourself only for lead-level work (review, decisions, owner communication, cross-team coordination), when every member is busy, or when the work truly needs your own judgment. "No member fits" is rare — a role mismatch is not a reason. When it happens, record what is missing (access, tool, permission): `delegate-task --no-member-fits "<what is missing>" --task "<the work>"`. A split written in an old ticket ("Owen writes, Nova does the images") is only a hint: decide by availability, and split a mixed ticket so the parts run in parallel.
|
|
106
|
+
|
|
107
|
+
**Owner requests from Slack.** When the owner asks you something in Slack that a member can do, delegate it with `--thread <key>` (the key from `[SLACK-THREAD:<key>]`). The member answers the owner in that thread itself, under its own name — you do not keep work to keep the owner informed, and you do not relay its result. A short "Sage is on it" from you is enough.
|
|
108
|
+
|
|
109
|
+
**Execution nudge.** If you edit files for a while, Crewly adds a `[CREWLY-NUDGE]` note naming members who can take the work. Delegate, or record why you keep it (`--no-member-fits`).
|
|
106
110
|
|
|
107
111
|
**The autopilot does not lift the approval boundary.** Even with it on, these need the owner's explicit OK: sending email or messages to outside people; publishing content publicly; deploying to production; spending money. Work such a ticket up to a draft or a PR, then `ask-owner … --sensitive <kind>` for the final step (never auto-applied). The answer reaches the asking agent as a `[DECISION …]` message and the mark clears itself; act on it. Withdraw a question that is no longer needed with `ask-owner --clear`.
|
|
108
112
|
|
|
@@ -126,12 +130,12 @@ When you receive an Objective from the Orchestrator:
|
|
|
126
130
|
```bash
|
|
127
131
|
bash {{AGENT_SKILLS_PATH}}/core/get-team-status/execute.sh '{}'
|
|
128
132
|
```
|
|
129
|
-
4. **Match task to worker** —
|
|
133
|
+
4. **Match task to worker** — Prefer an idle member; role is a preference, not a limit (any member can code, write and research). Don't overload a busy worker when an idle one is available.
|
|
130
134
|
5. **Delegate immediately** — Don't analyze endlessly. Once you have a clear task and an available worker, delegate. Speed matters.
|
|
131
135
|
|
|
132
136
|
#### Step 3: Task Delegation
|
|
133
|
-
1. Evaluate each worker's role
|
|
134
|
-
2. Use **delegate-task** to assign tasks to
|
|
137
|
+
1. Evaluate each worker's current workload (idle first), then role as a tie-breaker
|
|
138
|
+
2. Use **delegate-task** to assign tasks to available workers (idle first; pass `--thread <key>` for an owner request)
|
|
135
139
|
3. **Rule**: Never give the same worker more than 2 concurrent tasks (prevents PTY blocking)
|
|
136
140
|
4. Include clear acceptance criteria in every delegation
|
|
137
141
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: Ask Owner
|
|
3
|
-
description: Ask the owner ONE decision with 2–
|
|
3
|
+
description: Ask the owner ONE decision with 2–5 options, a default and a deadline. Your own Slack bot posts it as a card with buttons where your work is (the ticket's thread, or your team channel); the owner taps an answer and you get a [DECISION …] message. Never ask the owner open-ended questions in chat.
|
|
4
4
|
version: 1.0.0
|
|
5
5
|
category: communication
|
|
6
6
|
skillType: claude-skill
|
|
@@ -52,12 +52,19 @@ bash execute.sh --question "Send the partner email on Monday?" \
|
|
|
52
52
|
| Flag | Rule |
|
|
53
53
|
|---|---|
|
|
54
54
|
| `--question` | One line (8–280 characters). Name the decision, not "thoughts?" |
|
|
55
|
-
| `--option` | 2–
|
|
55
|
+
| `--option` | 2–5 times, one per alternative. `"Label"` or `"Label — detail"`. The label is the button (short, ≤ 40 characters). The owner picks exactly one; the answer comes back as that label. |
|
|
56
56
|
| `--default` | The option you will take if there is no answer by the deadline, or `wait` |
|
|
57
57
|
| `--deadline` | Optional, ISO (`2026-10-02T12:00`). Default: tomorrow 12:00 |
|
|
58
58
|
| `--ticket APP-12 --project P` | Optional. Ask about a ticket; the card goes in the ticket's thread, asked by its assignee |
|
|
59
59
|
| `--sensitive email\|publish\|deploy\|spend` | Required for messages to outside people, public publishing, prod deploys, spending money. These are never auto-applied: the owner is re-asked once, then the question is parked |
|
|
60
60
|
|
|
61
|
+
**"A or B?" is ONE card with options.** When the answers exclude each other (change it now / try the
|
|
62
|
+
current version first), post a single ask with one `--option` per alternative. Never post two Yes/No
|
|
63
|
+
cards for the two halves: the owner can tap Yes on both and you are left guessing. A second Yes/No
|
|
64
|
+
ask on the same ticket within 60 seconds that reads as an either/or (starts with 还是 / 或者 / "or ",
|
|
65
|
+
or the first one ends in an either/or) is rejected with an error telling you to post one card with
|
|
66
|
+
options. Use plain Yes/No only for a single question with one possible action.
|
|
67
|
+
|
|
61
68
|
What happens:
|
|
62
69
|
|
|
63
70
|
- The card is posted by your own Slack bot:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# ask-owner — one structured owner decision (question + 2–
|
|
2
|
+
# ask-owner — one structured owner decision (question + 2–5 options + default
|
|
3
3
|
# + deadline), posted as a Slack card by the asking agent's own bot.
|
|
4
4
|
# See specs/2026-10-01-decision-cards.md.
|
|
5
5
|
set -euo pipefail
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: Project Tickets
|
|
3
|
-
description: A project's own backlog — list, read, create, update, claim, release, assign, link, log and ask-owner (structured decision cards) on project tickets (markdown files in <project>/.crewly/tickets/, tracked in git), plus the per-project ticket autopilot switch, its stats
|
|
3
|
+
description: A project's own backlog — list, read, create, update, claim, release, assign, link, log and ask-owner (structured decision cards) on project tickets (markdown files in <project>/.crewly/tickets/, tracked in git), plus the per-project ticket autopilot switch, its speed mode, its stats, the daily retro and the self-review.
|
|
4
4
|
version: 1.1.0
|
|
5
5
|
category: task-management
|
|
6
6
|
skillType: claude-skill
|
|
@@ -102,6 +102,11 @@ bash execute.sh create --project P --title "Export the report as CSV" \
|
|
|
102
102
|
(orchestrator / team lead): create it with `--source request:<TKT id>` when
|
|
103
103
|
it came in as a harness ticket, and tell the owner the new ticket id. Do not
|
|
104
104
|
start working on it unless the owner asked for that too.
|
|
105
|
+
- **Tickets you open for a goal replan** must name the goal metric they move
|
|
106
|
+
and the expected effect: `--metric "<goal metric> → <expected effect>"`
|
|
107
|
+
(e.g. `--metric "weekly /feed visitors → +150"`). It is written as the
|
|
108
|
+
description's first line (`Metric: …`). Without it the create is refused
|
|
109
|
+
with a message saying so — add the metric and create it again.
|
|
105
110
|
|
|
106
111
|
## Change a ticket
|
|
107
112
|
|
|
@@ -129,7 +134,7 @@ without a WorkItem). Team leads also have the `assign-ticket` skill.
|
|
|
129
134
|
|
|
130
135
|
A **stopped** member is available: assigning starts it for the ticket (the
|
|
131
136
|
answer's `wake` says `started`, or which gate refused it — then it picks the
|
|
132
|
-
ticket up on its next start).
|
|
137
|
+
ticket up on its next start). Role is a preference, not a limit: prefer an idle member; keep only lead-level work.
|
|
133
138
|
|
|
134
139
|
## Link work already in flight (orchestrator / team lead)
|
|
135
140
|
|
|
@@ -158,7 +163,7 @@ bash execute.sh ask-owner --project P --id APP-12 \
|
|
|
158
163
|
bash execute.sh ask-owner --project P --id APP-12 --clear --note "resolved in the review call"
|
|
159
164
|
```
|
|
160
165
|
|
|
161
|
-
ONE question with 2–
|
|
166
|
+
ONE question with 2–5 options and a default (an option, or `wait`). The deadline defaults to
|
|
162
167
|
tomorrow at 12:00. The ticket's assignee, else the lead, posts the question as a card in the
|
|
163
168
|
ticket's Slack thread, using its own bot. The ticket gets `needs-owner` until the question is
|
|
164
169
|
answered.
|
|
@@ -179,6 +184,7 @@ bash execute.sh autopilot --project P # show settings + st
|
|
|
179
184
|
bash execute.sh autopilot --project P --on # switch on (the owner said so)
|
|
180
185
|
bash execute.sh autopilot --project P --on --daily-budget 20M --max-in-flight 1 # budget in tokens
|
|
181
186
|
bash execute.sh autopilot --project P --driver <lead session> # or --driver default
|
|
187
|
+
bash execute.sh autopilot --project P --speed rush # rush | normal | chill | default
|
|
182
188
|
bash execute.sh autopilot --project P --off
|
|
183
189
|
```
|
|
184
190
|
|
|
@@ -195,15 +201,41 @@ while an autopilot experiment on the project is running).
|
|
|
195
201
|
|
|
196
202
|
When the project has a goal (its goals log or an active project OKR) but
|
|
197
203
|
nothing is left to triage and someone on the team is idle, the team lead gets
|
|
198
|
-
ONE `goal_replan` WorkItem: the goal, the
|
|
199
|
-
any open experiment card, and the ask
|
|
200
|
-
or say why there are none". The lead
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
ONE `goal_replan` WorkItem: the goal, the lead's last self-review, the
|
|
205
|
+
tickets closed in the last 7 days, any open experiment card, and the ask
|
|
206
|
+
"open the next tickets toward this goal, or say why there are none". The lead
|
|
207
|
+
opens the tickets (each with `--metric`); the autopilot never makes them ready
|
|
208
|
+
or starts work. A replan still open after `--replan-ttl-hours` (default 4) is
|
|
209
|
+
expired. Only goals-log entries from the last 30 days count as an active goal.
|
|
210
|
+
|
|
211
|
+
**Speed** (`--speed`, the owner can also DM the orc "set CE to rush" /
|
|
212
|
+
"CE 切到 chill"):
|
|
213
|
+
|
|
214
|
+
| | Rush | Normal (default) | Chill |
|
|
215
|
+
|---|---|---|---|
|
|
216
|
+
| Replan when nothing is left | ≥ 1 h apart, ≤ 12 a day | ≥ 3 h apart, ≤ 4 a day | ≤ 1 a day |
|
|
217
|
+
| Self-review | hourly | daily | weekly |
|
|
218
|
+
| After a replan that opened nothing | retry in 1 h | next day | next week |
|
|
219
|
+
| Daily budget when none is set | 50M | 20M | 8M |
|
|
220
|
+
|
|
221
|
+
An explicit `--daily-budget` (and boosts) and `--replans-per-day <0-12>`
|
|
222
|
+
(0 = off) override the speed's. A new goal / OKR or a new ticket lifts the
|
|
223
|
+
wait after an empty replan.
|
|
224
|
+
|
|
225
|
+
**Self-review**: at the speed's cadence the lead gets one short
|
|
226
|
+
`autopilot_self_review` WorkItem (skipped when nothing changed and nobody is
|
|
227
|
+
idle, never for a paused team or over the budget). File it, then complete the
|
|
228
|
+
WorkItem:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
bash execute.sh self-review --project P --gap "620 of 1,000 weekly visitors" \
|
|
232
|
+
--moved "CE-41 feed cards (+90)" --next-bet "two feed cards a day on the top search queries"
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
The status (`autopilot --project P`) and the evening digest show the latest
|
|
236
|
+
self-review and why the autopilot stopped, if it did: `paused` (every team
|
|
237
|
+
paused), `budget_reached`, `system_error` (failed work / a wake that never
|
|
238
|
+
landed), `waiting_on_owner`, `no_ideas` (the last replan opened nothing).
|
|
207
239
|
|
|
208
240
|
## Autopilot numbers and retro (owner / orchestrator / team lead)
|
|
209
241
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
# bash execute.sh create --project P --title "…" [--description "…"] [--acceptance "…" …]
|
|
11
11
|
# [--priority P1] [--labels a,b] [--team <teamId>] [--status ready]
|
|
12
12
|
# [--source request:TKT-012] [--request-id <id>] [--owner-review]
|
|
13
|
+
# [--metric "<goal metric> → <expected effect>"]
|
|
13
14
|
# bash execute.sh update --project P --id APP-12 [--title …] [--priority …] [--labels …]
|
|
14
15
|
# [--description …] [--acceptance "…" …] [--status …] [--note "…"]
|
|
15
16
|
# bash execute.sh claim --project P --id APP-12
|
|
@@ -23,11 +24,12 @@
|
|
|
23
24
|
# bash execute.sh ask-owner --project P --id APP-12 --clear [--note "answer"]
|
|
24
25
|
# bash execute.sh autopilot --project P [--on|--off] [--driver <session>|--driver default]
|
|
25
26
|
# [--daily-budget <tokens, e.g. 20M>] [--max-in-flight <n>] (owner / orchestrator)
|
|
26
|
-
# [--retro on|off|default] [--replans-per-day <0-
|
|
27
|
-
# [--replan-ttl-hours <1-48>|default]
|
|
27
|
+
# [--retro on|off|default] [--replans-per-day <0-12>|default]
|
|
28
|
+
# [--replan-ttl-hours <1-48>|default] [--speed rush|normal|chill|default]
|
|
28
29
|
# bash execute.sh stats --project P [--days 14] [--label feed] (owner / orc / lead)
|
|
29
30
|
# bash execute.sh runs --project P [--days 7] [--label feed] (owner / orc / lead)
|
|
30
31
|
# bash execute.sh retro --project P --day YYYY-MM-DD --summary "…" [--problem "class|title|detail|evidence" …]
|
|
32
|
+
# bash execute.sh self-review --project P --gap "…" [--moved "…"] --next-bet "…"
|
|
31
33
|
# bash execute.sh '{"action":"create","project":"P","title":"…"}'
|
|
32
34
|
#
|
|
33
35
|
# P = project id, name, or absolute path.
|
|
@@ -44,6 +46,10 @@ Usage:
|
|
|
44
46
|
bash execute.sh create --project P --title "…" [--description "…"] [--acceptance "…" …]
|
|
45
47
|
[--priority P0-P3] [--labels a,b] [--team <teamId>] [--status backlog|ready]
|
|
46
48
|
[--source request:TKT-012] [--request-id <id>] [--owner-review]
|
|
49
|
+
[--metric "<goal metric> → <expected effect>"]
|
|
50
|
+
--metric: the goal metric the ticket moves and the
|
|
51
|
+
expected effect. Required for tickets you open during
|
|
52
|
+
a goal replan (refused without it)
|
|
47
53
|
bash execute.sh update --project P --id APP-12 [--title …] [--priority …] [--labels …]
|
|
48
54
|
[--description …] [--acceptance "…" …] [--status …] [--note "…"]
|
|
49
55
|
bash execute.sh claim --project P --id APP-12 Take a ready ticket (creates your WorkItem)
|
|
@@ -56,7 +62,7 @@ Usage:
|
|
|
56
62
|
flight (a live WorkItem) to this ticket
|
|
57
63
|
bash execute.sh ask-owner --project P --id APP-12 --question "…" --option "A" --option "B — detail"
|
|
58
64
|
--default "B"|wait [--deadline ISO] [--sensitive email|publish|deploy|spend]
|
|
59
|
-
Ask the owner ONE question with 2–
|
|
65
|
+
Ask the owner ONE question with 2–5 options. The
|
|
60
66
|
ticket's assignee (else its lead) posts it as a card
|
|
61
67
|
in the ticket's Slack thread; the answer comes back
|
|
62
68
|
to that agent as a [DECISION …] message
|
|
@@ -64,15 +70,17 @@ Usage:
|
|
|
64
70
|
The owner answered: remove the needs-owner mark
|
|
65
71
|
bash execute.sh autopilot --project P [--on|--off] [--driver <session>|default]
|
|
66
72
|
[--daily-budget <tokens, e.g. 20M>] [--max-in-flight <n>] [--retro on|off|default]
|
|
67
|
-
[--replans-per-day <0-
|
|
73
|
+
[--replans-per-day <0-12>|default] [--replan-ttl-hours <1-48>|default]
|
|
74
|
+
[--speed rush|normal|chill|default]
|
|
68
75
|
Owner / orchestrator: show or change the ticket
|
|
69
76
|
autopilot (no flags = show). --retro: the lead's
|
|
70
77
|
daily retro (default: on while an autopilot
|
|
71
|
-
experiment runs). --
|
|
72
|
-
day
|
|
73
|
-
|
|
74
|
-
--
|
|
75
|
-
|
|
78
|
+
experiment runs). --speed: Rush (replan ≥1 h apart,
|
|
79
|
+
≤12/day, hourly self-review), Normal (≥3 h, ≤4/day,
|
|
80
|
+
daily; the default) or Chill (≤1/day, weekly).
|
|
81
|
+
--replans-per-day: a hard daily cap that overrides
|
|
82
|
+
the speed's (0 = off); --replan-ttl-hours: a replan
|
|
83
|
+
still open after this long is expired (default 4)
|
|
76
84
|
bash execute.sh stats --project P [--days 14] [--label feed]
|
|
77
85
|
Autopilot numbers per day: tickets triaged /
|
|
78
86
|
started / done / verified / sent back / stalled,
|
|
@@ -85,6 +93,9 @@ Usage:
|
|
|
85
93
|
Team lead: file the daily autopilot retro.
|
|
86
94
|
class = agent_judgment | missing_skill |
|
|
87
95
|
harness_gap | owner_dependency
|
|
96
|
+
bash execute.sh self-review --project P --gap "…" [--moved "…"] --next-bet "…"
|
|
97
|
+
Team lead: file the autopilot self-review (gap to
|
|
98
|
+
the target, what moved it, the next bet)
|
|
88
99
|
|
|
89
100
|
P = project id, name or absolute path. Workers' new tickets start in backlog;
|
|
90
101
|
the owner, the orchestrator or a team lead makes them ready.
|
|
@@ -97,6 +108,7 @@ ACCEPTANCE_JSON="null"
|
|
|
97
108
|
HAS_DESCRIPTION=0
|
|
98
109
|
QUESTION=""; CLEAR=""; OPTIONS_JSON="[]"; DEFAULT_OPT=""; DEADLINE=""; SENSITIVE=""; AP_ENABLED=""; AP_DRIVER=""; AP_BUDGET=""; AP_MAX=""
|
|
99
110
|
AP_RETRO=""; AP_REPLANS=""; AP_REPLAN_TTL=""; DAYS=""; LABEL=""; DAY=""; SUMMARY=""; PROBLEMS_JSON="[]"
|
|
111
|
+
METRIC=""; AP_SPEED=""; GAP=""; MOVED=""; NEXT_BET=""
|
|
100
112
|
|
|
101
113
|
if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
|
|
102
114
|
J="$1"; shift
|
|
@@ -137,6 +149,11 @@ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
|
|
|
137
149
|
DAY=$(printf '%s' "$J" | jq -r '.day // empty')
|
|
138
150
|
SUMMARY=$(printf '%s' "$J" | jq -r '.summary // empty')
|
|
139
151
|
PROBLEMS_JSON=$(printf '%s' "$J" | jq -c 'if (.problems|type) == "array" then .problems else [] end')
|
|
152
|
+
METRIC=$(printf '%s' "$J" | jq -r '.metric // empty')
|
|
153
|
+
AP_SPEED=$(printf '%s' "$J" | jq -r '.speedMode // .speed // empty')
|
|
154
|
+
GAP=$(printf '%s' "$J" | jq -r '.gap // empty')
|
|
155
|
+
MOVED=$(printf '%s' "$J" | jq -r '.moved // empty')
|
|
156
|
+
NEXT_BET=$(printf '%s' "$J" | jq -r '.nextBet // empty')
|
|
140
157
|
fi
|
|
141
158
|
if [[ -z "$ACTION" && $# -gt 0 && ${1:0:1} != '-' ]]; then ACTION="$1"; shift; fi
|
|
142
159
|
|
|
@@ -184,13 +201,19 @@ while [[ $# -gt 0 ]]; do
|
|
|
184
201
|
--summary) [ $# -ge 2 ] || error_exit "--summary requires a value"; SUMMARY="$2"; shift 2 ;;
|
|
185
202
|
--problem) [ $# -ge 2 ] || error_exit "--problem requires \"class|title|detail|evidence\""
|
|
186
203
|
PROBLEMS_JSON=$(jq -c --arg p "$2" '. + [($p | split("|")) as $f | {class: ($f[0] // "" | gsub("^\\s+|\\s+$"; "")), title: ($f[1] // "")} + (if ($f[2] // "") != "" then {detail: $f[2]} else {} end) + (if ($f[3:] | join("|")) != "" then {evidence: ($f[3:] | join("|"))} else {} end)]' <<<"$PROBLEMS_JSON"); shift 2 ;;
|
|
204
|
+
--metric) [ $# -ge 2 ] || error_exit "--metric requires \"<goal metric> → <expected effect>\""; METRIC="$2"; shift 2 ;;
|
|
205
|
+
--speed|--speed-mode)
|
|
206
|
+
[ $# -ge 2 ] || error_exit "--speed requires rush, normal, chill or default"; AP_SPEED="$2"; shift 2 ;;
|
|
207
|
+
--gap) [ $# -ge 2 ] || error_exit "--gap requires a value"; GAP="$2"; shift 2 ;;
|
|
208
|
+
--moved) [ $# -ge 2 ] || error_exit "--moved requires a value"; MOVED="$2"; shift 2 ;;
|
|
209
|
+
--next-bet) [ $# -ge 2 ] || error_exit "--next-bet requires a value"; NEXT_BET="$2"; shift 2 ;;
|
|
187
210
|
--full) shift ;;
|
|
188
211
|
--help|-h) print_usage; exit 0 ;;
|
|
189
212
|
*) error_exit "Unknown option: $1" ;;
|
|
190
213
|
esac
|
|
191
214
|
done
|
|
192
215
|
|
|
193
|
-
[ -n "$ACTION" ] || { print_usage >&2; error_exit "Missing action: list | show | create | update | claim | release | assign | log | link | ask-owner | autopilot | stats | runs | retro"; }
|
|
216
|
+
[ -n "$ACTION" ] || { print_usage >&2; error_exit "Missing action: list | show | create | update | claim | release | assign | log | link | ask-owner | autopilot | stats | runs | retro | self-review"; }
|
|
194
217
|
|
|
195
218
|
# URL-encode a path segment (project paths contain slashes).
|
|
196
219
|
enc() { jq -rn --arg v "$1" '$v|@uri'; }
|
|
@@ -217,7 +240,9 @@ case "$ACTION" in
|
|
|
217
240
|
BODY=$(jq -n --arg title "$TITLE" --arg description "$DESCRIPTION" --argjson hasDescription "$HAS_DESCRIPTION" \
|
|
218
241
|
--arg priority "$PRIORITY" --arg labels "$LABELS" --arg team "$TEAM" --arg status "$STATUS" \
|
|
219
242
|
--arg source "$SOURCE" --arg requestId "$REQUEST_ID" --arg ownerReview "$OWNER_REVIEW" --argjson acceptance "$ACCEPTANCE_JSON" \
|
|
243
|
+
--arg metric "$METRIC" \
|
|
220
244
|
'{title: $title}
|
|
245
|
+
+ (if $metric != "" then {metric: $metric} else {} end)
|
|
221
246
|
+ (if $hasDescription == 1 then {description: $description} else {} end)
|
|
222
247
|
+ (if $acceptance != null then {acceptance: $acceptance} else {} end)
|
|
223
248
|
+ (if $priority != "" then {priority: $priority} else {} end)
|
|
@@ -294,11 +319,12 @@ case "$ACTION" in
|
|
|
294
319
|
;;
|
|
295
320
|
autopilot)
|
|
296
321
|
require_param "project" "$PROJECT"
|
|
297
|
-
if [ -z "$AP_ENABLED$AP_DRIVER$AP_BUDGET$AP_MAX$AP_RETRO$AP_REPLANS$AP_REPLAN_TTL" ]; then
|
|
322
|
+
if [ -z "$AP_ENABLED$AP_DRIVER$AP_BUDGET$AP_MAX$AP_RETRO$AP_REPLANS$AP_REPLAN_TTL$AP_SPEED" ]; then
|
|
298
323
|
api_call GET "/project-ticket-autopilot/$(enc "$PROJECT")" | jq '{success, autopilot: .data}'
|
|
299
324
|
else
|
|
300
|
-
BODY=$(jq -n --arg enabled "$AP_ENABLED" --arg driver "$AP_DRIVER" --arg budget "$AP_BUDGET" --arg max "$AP_MAX" --arg retro "$AP_RETRO" --arg replans "$AP_REPLANS" --arg ttl "$AP_REPLAN_TTL" \
|
|
325
|
+
BODY=$(jq -n --arg enabled "$AP_ENABLED" --arg driver "$AP_DRIVER" --arg budget "$AP_BUDGET" --arg max "$AP_MAX" --arg retro "$AP_RETRO" --arg replans "$AP_REPLANS" --arg ttl "$AP_REPLAN_TTL" --arg speed "$AP_SPEED" \
|
|
301
326
|
'{}
|
|
327
|
+
+ (if $speed == "default" then {speedMode: null} elif $speed != "" then {speedMode: $speed} else {} end)
|
|
302
328
|
+ (if $enabled != "" then {enabled: ($enabled == "true")} else {} end)
|
|
303
329
|
+ (if $retro == "default" then {retro: null} elif $retro != "" then {retro: $retro} else {} end)
|
|
304
330
|
+ (if $replans == "default" then {replansPerDay: null} elif $replans != "" then {replansPerDay: ($replans | tonumber? // $replans)} else {} end)
|
|
@@ -329,7 +355,14 @@ case "$ACTION" in
|
|
|
329
355
|
BODY=$(jq -n --arg d "$DAY" --arg s "$SUMMARY" --argjson p "$PROBLEMS_JSON" '{day: $d, summary: $s, problems: $p}')
|
|
330
356
|
api_call POST "/project-ticket-autopilot/$(enc "$PROJECT")/retro" "$BODY" | jq '{success, retro: .data, error}'
|
|
331
357
|
;;
|
|
358
|
+
self-review)
|
|
359
|
+
require_param "project" "$PROJECT"
|
|
360
|
+
require_param "gap (--gap)" "$GAP"
|
|
361
|
+
require_param "next bet (--next-bet)" "$NEXT_BET"
|
|
362
|
+
BODY=$(jq -n --arg g "$GAP" --arg m "$MOVED" --arg n "$NEXT_BET" '{gap: $g, nextBet: $n} + (if $m != "" then {moved: $m} else {} end)')
|
|
363
|
+
api_call POST "/project-ticket-autopilot/$(enc "$PROJECT")/self-review" "$BODY" | jq '{success, selfReview: .data, error}'
|
|
364
|
+
;;
|
|
332
365
|
*)
|
|
333
|
-
error_exit "Unknown action: $ACTION (use list | show | create | update | claim | release | assign | log | link | ask-owner | autopilot | stats | runs | retro)"
|
|
366
|
+
error_exit "Unknown action: $ACTION (use list | show | create | update | claim | release | assign | log | link | ask-owner | autopilot | stats | runs | retro | self-review)"
|
|
334
367
|
;;
|
|
335
368
|
esac
|
|
@@ -88,6 +88,12 @@ run create --project p1 --title "Export CSV" --description "why" --acceptance "h
|
|
|
88
88
|
check "create: path" "$(last .path)" "/api/project-tickets/p1"
|
|
89
89
|
check "create: body" "$(last '.body | tostring')" '{"title":"Export CSV","description":"why","acceptance":["header row","opens in Excel"],"priority":"P1","labels":["ui","export"],"source":"request:TKT-012"}'
|
|
90
90
|
|
|
91
|
+
# --- create with the goal metric (required for goal-replan tickets) ---
|
|
92
|
+
run create --project p1 --title "Feed card 3" --metric "weekly /feed visitors → +150" --status ready >/dev/null
|
|
93
|
+
check "create metric: body" "$(last '.body | tostring')" '{"title":"Feed card 3","metric":"weekly /feed visitors → +150","status":"ready"}'
|
|
94
|
+
run '{"action":"create","project":"p1","title":"From JSON metric","metric":"returning visitors → +5%"}' >/dev/null
|
|
95
|
+
check "create json metric: body" "$(last '.body | tostring')" '{"title":"From JSON metric","metric":"returning visitors → +5%"}'
|
|
96
|
+
|
|
91
97
|
# --- create from JSON input ---
|
|
92
98
|
run '{"action":"create","project":"p1","title":"From JSON","status":"ready","ownerReview":true}' >/dev/null
|
|
93
99
|
check "create json: body" "$(last '.body | tostring')" '{"title":"From JSON","status":"ready","ownerReview":true}'
|
|
@@ -165,6 +171,19 @@ check "autopilot replans default: body" "$(last '.body | tostring')" '{"replansP
|
|
|
165
171
|
run autopilot --project p1 --replan-ttl-hours 6 >/dev/null
|
|
166
172
|
check "autopilot replan ttl: body" "$(last '.body | tostring')" '{"replanTtlHours":6}'
|
|
167
173
|
|
|
174
|
+
run autopilot --project p1 --speed rush >/dev/null
|
|
175
|
+
check "autopilot speed: body" "$(last '.body | tostring')" '{"speedMode":"rush"}'
|
|
176
|
+
run autopilot --project p1 --speed default >/dev/null
|
|
177
|
+
check "autopilot speed default: body" "$(last '.body | tostring')" '{"speedMode":null}'
|
|
178
|
+
run '{"action":"autopilot","project":"p1","speedMode":"chill"}' >/dev/null
|
|
179
|
+
check "autopilot speed json: body" "$(last '.body | tostring')" '{"speedMode":"chill"}'
|
|
180
|
+
|
|
181
|
+
# --- self-review (specs/2026-10-04-autopilot-speed-modes.md) ---
|
|
182
|
+
run self-review --project p1 --gap "620 of 1,000 weekly visitors" --moved "CE-41 feed cards" --next-bet "two cards a day on the top queries" >/dev/null
|
|
183
|
+
check "self-review: path" "$(last .path)" "/api/project-ticket-autopilot/p1/self-review"
|
|
184
|
+
check "self-review: body" "$(last '.body | tostring')" '{"gap":"620 of 1,000 weekly visitors","nextBet":"two cards a day on the top queries","moved":"CE-41 feed cards"}'
|
|
185
|
+
check "self-review: missing next bet" "$(run_err self-review --project p1 --gap x | grep -c 'next bet')" "1"
|
|
186
|
+
|
|
168
187
|
# --- stats / runs / retro (specs/2026-10-03-autopilot-experiments.md) ---
|
|
169
188
|
OUT=$(run stats --project p1 --days 7 --label feed)
|
|
170
189
|
check "stats: path" "$(last .path)" "/api/project-ticket-autopilot/p1/stats?days=7&label=feed"
|
|
@@ -49,6 +49,46 @@ Assigns a task to a worker within the Team Leader's subordinate scope. Validates
|
|
|
49
49
|
| `--from` | `fromSession` | No | Delegating TL's session name (for monitoring) |
|
|
50
50
|
| `--request-id` / `-R` | `requestId` | No | Ticket this work is for: the id (or `TKT-123`) from the `[TICKET:TKT-123 <id>]` line of the message you are acting on. Omit it and the task is still linked when your current turn has exactly one ticket |
|
|
51
51
|
| `--ticket` | `ticket` | No | Project ticket this work is for (e.g. `APP-12`). Without it a ticket is created for you when the target works on a project — see Project tickets |
|
|
52
|
+
| `--thread` | `thread` | No | Owner request from Slack: the key from the `[SLACK-THREAD:<key>]` of the owner's message. The member answers the owner in that thread itself — see Owner requests |
|
|
53
|
+
| `--no-member-fits` | `noMemberFits` | No | You keep the work: record what is missing (access, tool, permission, everyone busy). Needs `--task`; nothing is delegated — see No member fits |
|
|
54
|
+
| `--work-item` | `workItemId` | No | With `--no-member-fits`: the WorkItem you keep (gets a `[NO-MEMBER-FITS]` note) |
|
|
55
|
+
|
|
56
|
+
## Who to delegate to
|
|
57
|
+
|
|
58
|
+
Role is a preference, not a limit: every member runs the same runtime and can
|
|
59
|
+
code, write and research. Any member can take any work that needs no special
|
|
60
|
+
account, tool or permission. Prefer an idle (or stopped) member over doing it
|
|
61
|
+
yourself. Do hands-on work yourself only for lead-level work (review,
|
|
62
|
+
decisions, owner communication, cross-team coordination), when every member
|
|
63
|
+
is busy, or when the work truly needs your own judgment.
|
|
64
|
+
|
|
65
|
+
## Owner requests (`--thread`)
|
|
66
|
+
|
|
67
|
+
When the owner asked in Slack, pass the thread key from the owner message's
|
|
68
|
+
`[SLACK-THREAD:<key>]`:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
bash execute.sh --to sage-session --task "Goal: … Outcome: … Eval: …" --thread C0THINK:1790000000.000100
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The WorkItem carries the thread and the member is told to post its progress
|
|
75
|
+
and result there itself (`reply --work-item <id>`), under its own name. You do
|
|
76
|
+
not relay its answer; the room's reply gate never holds the member's post.
|
|
77
|
+
Without `--thread` the thread of your last owner message is used. (A thread
|
|
78
|
+
in your DM with the owner: the member's bot cannot post there, so it answers
|
|
79
|
+
in its own DM with the owner, opened with `Re: <task>`.)
|
|
80
|
+
|
|
81
|
+
## No member fits (`--no-member-fits`)
|
|
82
|
+
|
|
83
|
+
Rare. When you keep work yourself, record why — what is missing, not a role
|
|
84
|
+
mismatch — so the owner sees missing roles in the daily report:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
bash execute.sh --no-member-fits "needs the owner's Stripe login" --task "Update billing settings" [--work-item <id>] [--ticket CE-7]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Nothing is delivered. With `--work-item` the WorkItem gets a
|
|
91
|
+
`[NO-MEMBER-FITS] <reason>` note.
|
|
52
92
|
|
|
53
93
|
## Project tickets
|
|
54
94
|
|