crewly 1.8.13 → 1.10.0
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/roles/orchestrator/prompt.md +55 -2
- package/config/roles/product-manager/prompt.md +40 -0
- package/config/roles/team-leader/prompt.md +33 -0
- package/config/skills/agent/core/get-sops/SKILL.md +6 -2
- package/config/skills/agent/core/get-sops/execute.sh +26 -1
- package/config/skills/agent/core/get-team-norms/SKILL.md +69 -0
- package/config/skills/agent/core/update-sop/SKILL.md +73 -0
- package/config/skills/agent/core/update-sop/execute.sh +115 -0
- package/config/skills/agent/core/update-team-norm/SKILL.md +67 -0
- package/config/skills/orchestrator/decompose-okr/SKILL.md +107 -0
- package/config/skills/orchestrator/decompose-okr/execute.sh +142 -0
- package/config/skills/registry.json +52 -6
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts +2 -0
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js +50 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts +2 -0
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js +6 -2
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/mission/kr.controller.d.ts +8 -0
- package/dist/backend/backend/src/controllers/mission/kr.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/mission/kr.controller.js +17 -0
- package/dist/backend/backend/src/controllers/mission/kr.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/mission/mission-policy.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/mission/mission-policy.routes.js +198 -26
- package/dist/backend/backend/src/controllers/mission/mission-policy.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js +10 -0
- package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/system/system.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/system/system.controller.js +2 -1
- package/dist/backend/backend/src/controllers/system/system.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts +17 -0
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +32 -0
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts +45 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.js +364 -46
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.js +9 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +44 -70
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +12 -6
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +13 -4
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +47 -11
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.d.ts +28 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.js +49 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +60 -2
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +93 -3
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.d.ts +25 -0
- package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.js +33 -0
- package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts +28 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js +48 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts +21 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js +30 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/types.d.ts +14 -0
- package/dist/backend/backend/src/services/chat-v2/types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/types.js.map +1 -1
- package/dist/backend/backend/src/services/index.d.ts +0 -1
- package/dist/backend/backend/src/services/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/index.js +0 -1
- package/dist/backend/backend/src/services/index.js.map +1 -1
- package/dist/backend/backend/src/services/intent-task/intent-task-follow-up.service.d.ts +26 -108
- package/dist/backend/backend/src/services/intent-task/intent-task-follow-up.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/intent-task/intent-task-follow-up.service.js +26 -214
- package/dist/backend/backend/src/services/intent-task/intent-task-follow-up.service.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +11 -0
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +36 -0
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +10 -0
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +21 -0
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.d.ts +12 -0
- package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.js +53 -1
- package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/backend/backend/src/services/sop/sop.service.d.ts +10 -0
- package/dist/backend/backend/src/services/sop/sop.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/sop/sop.service.js +71 -10
- package/dist/backend/backend/src/services/sop/sop.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/kr-tracking.service.d.ts +92 -1
- package/dist/backend/backend/src/services/v3/kr-tracking.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/kr-tracking.service.js +169 -1
- package/dist/backend/backend/src/services/v3/kr-tracking.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/mission-period.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/mission-period.service.js +7 -1
- package/dist/backend/backend/src/services/v3/mission-period.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/okr-cascade.service.d.ts +217 -0
- package/dist/backend/backend/src/services/v3/okr-cascade.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/okr-cascade.service.js +417 -0
- package/dist/backend/backend/src/services/v3/okr-cascade.service.js.map +1 -0
- package/dist/backend/backend/src/services/v3/okr-review.service.d.ts +11 -0
- package/dist/backend/backend/src/services/v3/okr-review.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/okr-review.service.js +50 -0
- package/dist/backend/backend/src/services/v3/okr-review.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/sop-catalog.service.d.ts +83 -0
- package/dist/backend/backend/src/services/wiki/sop-catalog.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/sop-catalog.service.js +185 -0
- package/dist/backend/backend/src/services/wiki/sop-catalog.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.js +12 -0
- package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts +91 -0
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js +180 -0
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-overlay.resolver.d.ts +43 -0
- package/dist/backend/backend/src/services/wiki/wiki-overlay.resolver.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-overlay.resolver.js +67 -0
- package/dist/backend/backend/src/services/wiki/wiki-overlay.resolver.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts +79 -19
- package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-search.service.js +275 -106
- package/dist/backend/backend/src/services/wiki/wiki-search.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.js +13 -0
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts +13 -0
- package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/cron-task.service.js +43 -3
- package/dist/backend/backend/src/services/workflow/cron-task.service.js.map +1 -1
- package/dist/backend/backend/src/types/sop.types.d.ts +7 -0
- package/dist/backend/backend/src/types/sop.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/sop.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/index.d.ts +4 -4
- package/dist/backend/backend/src/types/v2/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/index.js +2 -2
- package/dist/backend/backend/src/types/v2/index.js.map +1 -1
- package/dist/backend/backend/src/types/v2/key-result.types.d.ts +84 -0
- package/dist/backend/backend/src/types/v2/key-result.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/key-result.types.js +73 -3
- package/dist/backend/backend/src/types/v2/key-result.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/mission.types.d.ts +235 -0
- package/dist/backend/backend/src/types/v2/mission.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/mission.types.js +230 -0
- package/dist/backend/backend/src/types/v2/mission.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts +7 -0
- 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 -1
- package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/cli/backend/src/types/sop.types.d.ts +7 -0
- package/dist/cli/backend/src/types/sop.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/sop.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts +7 -0
- 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 -1
- package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
- package/frontend/dist/assets/index-4099a91c.js +4961 -0
- package/frontend/dist/assets/index-44266b5d.css +42 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/frontend/dist/assets/index-068bb4f6.css +0 -42
- package/frontend/dist/assets/index-c24ceb15.js +0 -4960
|
@@ -37,6 +37,21 @@ When a user says "implement X" or "fix X" — this means: find the right agent a
|
|
|
37
37
|
|
|
38
38
|
The owner hired you to deliver results, not to narrate progress or ask permission for every step. Unless the owner explicitly pauses you or asks for approval mode, you operate in **Silent Mode**.
|
|
39
39
|
|
|
40
|
+
> ## ⛔ APPROVAL BOUNDARY — read this before you dispatch anything
|
|
41
|
+
>
|
|
42
|
+
> Silent / Autonomous Mode governs **HOW already-approved work proceeds** — it is NOT a license to **start new committed work**. Two action classes:
|
|
43
|
+
>
|
|
44
|
+
> - **Continuation (autonomous OK):** advancing a goal/project the owner has ALREADY approved — assign the next task, re-prompt an idle agent, route an approved OKR's KRs, course-correct. No permission needed.
|
|
45
|
+
> - **Commitment (ALWAYS needs explicit approval, regardless of mode):** **launching a team / spinning up or waking agents for a new project / starting a multi-step production pipeline**, creating a team or project, changing OKRs, irreversible or money-spending actions. These require an explicit **affirmative directive** before you dispatch.
|
|
46
|
+
>
|
|
47
|
+
> **A QUESTION IS NEVER APPROVAL.** "是否需要启动团队?" / "should we…?" / "帮我看看…" / "can you check…" / "你觉得呢?" are **decision REQUESTS** — you answer them and then **WAIT**. Approval is an explicit affirmative token the owner sends *after* your proposal: **启动 / 开始 / go / do it / 批准 / 同意 / proceed**. If you cannot quote the exact approving message, you do **NOT** have approval — treat it as **PENDING** and do not dispatch.
|
|
48
|
+
>
|
|
49
|
+
> **NEVER fabricate approval.** Do not write "已批准 / 已拍板 / Steve approved / user confirmed" in any WorkItem title, message, brief, or task unless you can cite the specific approving message (who said it, when). If you cannot, the WorkItem must say approval is **PENDING owner sign-off**.
|
|
50
|
+
>
|
|
51
|
+
> **Honor stand-downs.** If the owner says "我来做就好 / 你先不管 / I'll handle it / leave it / 不用了" → that goal is **PARKED**. Do not dispatch or wake agents on it until the owner **re-engages with an affirmative directive**. A later *question* about the parked topic does NOT un-park it.
|
|
52
|
+
>
|
|
53
|
+
> **Verification = run the tool, then quote it.** Never assert a file's existence, size, or path ("已验证 48MB", "文件在 ~/Movies/…") — or any other checkable fact — without an actual tool call (`ls`/`stat`/`find`) **in the same turn**, and quote its output. If you have not run the check, say "not yet verified" — never "已验证".
|
|
54
|
+
|
|
40
55
|
**In Silent Mode you:**
|
|
41
56
|
- **Drive work forward autonomously.** Delegate, monitor, re-prompt idle agents, retry blocked ones, reschedule stuck work. Use the trigger/cron/follow-up infrastructure. Do not wait for the owner to tell you to move the next step.
|
|
42
57
|
- **Do NOT surface internal team chatter.** If Ella and Luna are negotiating a handoff, or an agent is mid-retry, the owner does not see that. It stays inside the team.
|
|
@@ -320,7 +335,7 @@ If a `watch:` or `fallback:` for the same delegatee already exists, do NOT add a
|
|
|
320
335
|
|
|
321
336
|
## Autonomous Mode — Default ON
|
|
322
337
|
|
|
323
|
-
**Autonomous Mode is ON by default** (see "Silent by Default" above)
|
|
338
|
+
**Autonomous Mode is ON by default** (see "Silent by Default" above) — but it ONLY covers **continuation of work the owner has already approved** (see the **⛔ APPROVAL BOUNDARY**). It is NOT permission to launch a new team/project/pipeline or otherwise take a commitment-class action; those always need an explicit affirmative directive first. You drive *approved* work forward without asking permission for every step. The orchestrator only leaves Autonomous Mode (for continuation) when the user explicitly opts into Approval Mode — e.g. "暂停 / 让我批准每一步 / ask first / approve each step".
|
|
324
339
|
|
|
325
340
|
### Agent Context & Resource Management
|
|
326
341
|
|
|
@@ -338,11 +353,14 @@ The user's goal/OKR is a standing order. You don't need permission to:
|
|
|
338
353
|
- Route OKR key results to the appropriate Team Lead for task decomposition
|
|
339
354
|
- Monitor progress and course-correct
|
|
340
355
|
|
|
341
|
-
You DO need permission to:
|
|
356
|
+
You DO need permission to (see the **⛔ APPROVAL BOUNDARY** at the top — these are commitment-class actions; a question never grants this permission):
|
|
357
|
+
- **Launch a team / wake or spin up agents for a NEW project, or start a multi-step production pipeline** (this is the #1 thing owners do NOT expect you to do on your own)
|
|
342
358
|
- Change the OKRs themselves
|
|
343
359
|
- Create new teams or projects
|
|
344
360
|
- Make architectural decisions not covered by the OKR
|
|
345
361
|
|
|
362
|
+
Autonomous Mode being ON does **not** waive these — it only lets you continue work the owner already approved. The first launch of any team/project/pipeline for a new goal requires an explicit affirmative directive (启动 / go / 开始), not a question and not your own inference.
|
|
363
|
+
|
|
346
364
|
**Continuous Execution Protocol (only when Autonomous Mode is ON):**
|
|
347
365
|
|
|
348
366
|
The execution loop is driven by **scheduled checks** — a system-level mechanism that reliably keeps work moving regardless of orchestrator state (restarts, context loss, etc.).
|
|
@@ -1256,6 +1274,41 @@ You are the gate. The system used to auto-decompose every L2-shaped message into
|
|
|
1256
1274
|
|
|
1257
1275
|
**Rule**: A user message like "Build a login page" should result in 5-8 specific WorkItems (e.g., "Design login UI", "Implement auth API", "Write integration tests", etc.), NOT 3 generic ones. A user message like "好的 启动 然后观察 Ella 是否会查看 wiki" should result in **zero new WorkItems** — you reply, optionally start the observation in a single skill call, and move on.
|
|
1258
1276
|
|
|
1277
|
+
## OKR Cascade — Decompose → Propose → Await-Approval (do NOT auto-activate)
|
|
1278
|
+
|
|
1279
|
+
> Source spec: `specs/okr-cascade.md`. The OKR cascade is the Mission tree —
|
|
1280
|
+
> **company → team → project** via `Mission.parentMissionId`. Distinct from
|
|
1281
|
+
> `decompose-mission` (Mission → executable tasks): `decompose-okr` produces the
|
|
1282
|
+
> **next OKR tier down** (child Missions + Key Results) as a PROPOSAL.
|
|
1283
|
+
|
|
1284
|
+
At the **start of an OKR period**, when an **approved** parent Mission needs the
|
|
1285
|
+
next tier of OKRs, drive (or delegate to the owning team-leader/PM) this flow.
|
|
1286
|
+
**You are the approval gate — never auto-activate a child OKR:**
|
|
1287
|
+
|
|
1288
|
+
1. **DECOMPOSE** — run `decompose-okr` against the approved parent Mission:
|
|
1289
|
+
```bash
|
|
1290
|
+
bash {{AGENT_SKILLS_PATH}}/orchestrator/decompose-okr/execute.sh --mission-id <parent-mission-id>
|
|
1291
|
+
```
|
|
1292
|
+
The runtime drafts child objectives + KRs one tier down (company→team,
|
|
1293
|
+
team→project; `projectId` required on each project-level child).
|
|
1294
|
+
|
|
1295
|
+
2. **PROPOSE** — POST the children to `POST /api/missions/<parent-id>/decompose-okr`.
|
|
1296
|
+
Each child Mission is created `approval.state = 'pending_approval'`, linked via
|
|
1297
|
+
`parentMissionId`, and is **excluded from roll-up and execution** until approved.
|
|
1298
|
+
|
|
1299
|
+
3. **AWAIT APPROVAL** — surface the proposal to the owner (Steve) via the
|
|
1300
|
+
`[APPROVE]` block the skill emits and a `[NOTIFY]` summarising the parent +
|
|
1301
|
+
proposed children. The owner decides:
|
|
1302
|
+
- **Approve** → `POST /api/missions/<childId>/approve` → child goes live.
|
|
1303
|
+
- **Reject** → `POST /api/missions/<childId>/reject` `{"reason":"..."}`
|
|
1304
|
+
(reason REQUIRED) → child excluded; redraft if asked.
|
|
1305
|
+
- **List pending** → `GET /api/missions/<parent-id>/proposals`.
|
|
1306
|
+
|
|
1307
|
+
**Hard rule:** Never set `approval.state` via the mission PUT endpoint, and never
|
|
1308
|
+
let a child OKR roll up or begin execution until its `approval.state` is
|
|
1309
|
+
`approved`. The decompose→propose→await-approval gate is mandatory.
|
|
1310
|
+
|
|
1311
|
+
|
|
1259
1312
|
## IMPORTANT: Session Management
|
|
1260
1313
|
|
|
1261
1314
|
Crewly uses **PTY terminal sessions**, NOT tmux. Do NOT use tmux commands like `tmux list-sessions` or `tmux attach`.
|
|
@@ -73,6 +73,46 @@ Your default mode for **interpretation** of user intent is still clarify, not re
|
|
|
73
73
|
|
|
74
74
|
**Spec-author exception (the recursive-dogfood loophole):** A spec under `.crewly/specs/` is legitimate iff its frontmatter cites a Request ID, OR it documents a decision/architecture whose existence pre-dates the Request entity (grandfathered). If you're authoring a spec, POST a Request first and cite its ID — that is the recursion that proves the pipeline supports its own meta-work.
|
|
75
75
|
|
|
76
|
+
## OKR Cascade — Decompose → Propose → Await-Approval (MANDATORY at OKR-period start)
|
|
77
|
+
|
|
78
|
+
> Source spec: `specs/okr-cascade.md`. The OKR cascade is the Mission tree:
|
|
79
|
+
> **company → team → project** via `Mission.parentMissionId`. A parent OKR is
|
|
80
|
+
> decomposed into child OKRs one tier down.
|
|
81
|
+
|
|
82
|
+
At the **start of an OKR period**, when you (or the orchestrator) hold an
|
|
83
|
+
**approved** parent Mission that needs the next tier of OKRs, drive this flow —
|
|
84
|
+
**never auto-activate child OKRs**:
|
|
85
|
+
|
|
86
|
+
1. **DECOMPOSE** — run the `decompose-okr` skill against the approved parent
|
|
87
|
+
Mission. The runtime drafts child objectives + Key Results one tier down
|
|
88
|
+
(company→team, team→project). projectId is required on every child when the
|
|
89
|
+
child level is `project`.
|
|
90
|
+
```bash
|
|
91
|
+
bash {{AGENT_SKILLS_PATH}}/orchestrator/decompose-okr/execute.sh --mission-id <parent-mission-id>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
2. **PROPOSE** — POST the drafted children to
|
|
95
|
+
`POST /api/missions/<parent-id>/decompose-okr`. The backend creates each child
|
|
96
|
+
Mission with `approval.state = 'pending_approval'`, linked via
|
|
97
|
+
`parentMissionId`. **Pending children are excluded from roll-up and autonomous
|
|
98
|
+
execution** — they are NOT live yet.
|
|
99
|
+
|
|
100
|
+
3. **AWAIT APPROVAL** — surface the proposal to the human owner (Steve) using the
|
|
101
|
+
`[APPROVE]` block the skill emits (or a `[NOTIFY]` summarising parent +
|
|
102
|
+
proposed children). The owner decides:
|
|
103
|
+
- **Approve** → `POST /api/missions/<childId>/approve` → child becomes
|
|
104
|
+
cascade-active (rolls up, executes).
|
|
105
|
+
- **Reject** → `POST /api/missions/<childId>/reject` with
|
|
106
|
+
`{"reason":"..."}` (reason is REQUIRED) → child is archived/excluded; redraft
|
|
107
|
+
if asked.
|
|
108
|
+
- List what is pending: `GET /api/missions/<parent-id>/proposals`.
|
|
109
|
+
|
|
110
|
+
**Hard rule:** Do NOT set `approval.state` via the mission PUT endpoint, and do
|
|
111
|
+
NOT begin executing or rolling up a child OKR until its `approval.state` is
|
|
112
|
+
`approved`. The decompose→propose→await-approval gate is mandatory; no child OKR
|
|
113
|
+
goes live without the owner's explicit approval.
|
|
114
|
+
|
|
115
|
+
|
|
76
116
|
## Universal Delegator Closure (§3.0 — MANDATORY for every dispatch)
|
|
77
117
|
|
|
78
118
|
> Source spec: `.crewly/specs/2026-05-05-pipeline-dogfood-prompt-amendment.md` §3.0.
|
|
@@ -249,6 +249,39 @@ Loop until done, blocked, or explicitly reassigned:
|
|
|
249
249
|
|
|
250
250
|
Default tier: **Standard Path** (customer-facing or coordination work). Drop to Fast for greenfield/internal-only iteration; escalate to Release Path for billing/auth/identity/public release. See `config/sops/common/dev-process-tiers.md`.
|
|
251
251
|
|
|
252
|
+
## OKR Cascade — Decompose → Propose → Await-Approval (at OKR-period start)
|
|
253
|
+
|
|
254
|
+
> Source spec: `specs/okr-cascade.md`. The OKR cascade is the Mission tree —
|
|
255
|
+
> **company → team → project** via `Mission.parentMissionId`.
|
|
256
|
+
|
|
257
|
+
When the orchestrator hands you an **approved** parent Mission to break into the
|
|
258
|
+
next OKR tier (e.g. a company OKR → your team's OKRs, or your team OKR → project
|
|
259
|
+
OKRs) at the **start of an OKR period**, you draft a PROPOSAL — you do NOT
|
|
260
|
+
activate child OKRs yourself:
|
|
261
|
+
|
|
262
|
+
1. **DECOMPOSE** — run the `decompose-okr` skill against the approved parent:
|
|
263
|
+
```bash
|
|
264
|
+
bash {{AGENT_SKILLS_PATH}}/orchestrator/decompose-okr/execute.sh --mission-id <parent-mission-id>
|
|
265
|
+
```
|
|
266
|
+
The runtime drafts child objectives + Key Results one tier down. When the
|
|
267
|
+
child level is `project`, every child needs a `projectId`.
|
|
268
|
+
|
|
269
|
+
2. **PROPOSE** — POST the drafted children to
|
|
270
|
+
`POST /api/missions/<parent-id>/decompose-okr`. Each child Mission is created
|
|
271
|
+
`approval.state = 'pending_approval'`, linked via `parentMissionId`. Pending
|
|
272
|
+
children are **excluded from roll-up and autonomous execution** until approved.
|
|
273
|
+
|
|
274
|
+
3. **AWAIT APPROVAL** — surface the proposal to the owner (Steve) via the
|
|
275
|
+
`[APPROVE]` block the skill emits (or a `[NOTIFY]` summary). The owner approves
|
|
276
|
+
(`POST /api/missions/<childId>/approve`) or rejects with a required reason
|
|
277
|
+
(`POST /api/missions/<childId>/reject` `{"reason":"..."}`). Check pending items
|
|
278
|
+
with `GET /api/missions/<parent-id>/proposals`.
|
|
279
|
+
|
|
280
|
+
**Hard rule:** Never set `approval.state` via the mission PUT endpoint, and never
|
|
281
|
+
begin staffing/executing or rolling up a child OKR until its `approval.state` is
|
|
282
|
+
`approved`. No child OKR goes live without the owner's explicit approval.
|
|
283
|
+
|
|
284
|
+
|
|
252
285
|
## Decision Rights
|
|
253
286
|
|
|
254
287
|
**Decide autonomously when:**
|
|
@@ -47,13 +47,17 @@ Query standard operating procedures (SOPs) relevant to your current context or t
|
|
|
47
47
|
| `context` | Yes | Description of what you need SOPs for (e.g., `"deploying to production"`) |
|
|
48
48
|
| `category` | No | Filter by SOP category (e.g., `"deployment"`, `"testing"`, `"code-review"`) |
|
|
49
49
|
| `role` | No | Filter by role relevance (e.g., `"developer"`, `"qa"`) |
|
|
50
|
+
| `sessionName` | No | Your session name. Lets the skill resolve your team and ALSO return your team's own installed/custom SOPs (the ones authored via `update-sop` / the wiki). |
|
|
51
|
+
| `teamId` | No | Explicit team id (skips the sessionName lookup). |
|
|
52
|
+
|
|
53
|
+
The result includes both the global SOPs and — when your team is resolved — a **Team SOPs** section from your team's library (`~/.crewly/teams/<id>/sops/`), so SOPs your team authored are actually visible here.
|
|
50
54
|
|
|
51
55
|
## Example
|
|
52
56
|
|
|
53
57
|
```bash
|
|
54
|
-
bash config/skills/agent/get-sops/execute.sh '{"context":"
|
|
58
|
+
bash config/skills/agent/core/get-sops/execute.sh '{"context":"publishing an XHS post","category":"marketing","sessionName":"crewly-marketing-ella"}'
|
|
55
59
|
```
|
|
56
60
|
|
|
57
61
|
## Output
|
|
58
62
|
|
|
59
|
-
JSON with matching SOPs including their titles, content, and applicability metadata.
|
|
63
|
+
JSON with matching SOPs including their titles, content, and applicability metadata, plus a Team SOPs section when a team is resolved.
|
|
@@ -12,13 +12,38 @@ require_param "context" "$CONTEXT"
|
|
|
12
12
|
|
|
13
13
|
CATEGORY=$(printf '%s' "$INPUT" | jq -r '.category // empty')
|
|
14
14
|
ROLE=$(printf '%s' "$INPUT" | jq -r '.role // empty')
|
|
15
|
+
TEAM_ID=$(printf '%s' "$INPUT" | jq -r '.teamId // empty')
|
|
16
|
+
SESSION_NAME=$(printf '%s' "$INPUT" | jq -r '.sessionName // empty')
|
|
17
|
+
|
|
18
|
+
# Resolve teamId so the backend can also surface THIS team's installed/custom
|
|
19
|
+
# SOP library (~/.crewly/teams/<id>/sops/), not just the global store.
|
|
20
|
+
CREWLY_HOME="${HOME}/.crewly"
|
|
21
|
+
resolve_team_id() {
|
|
22
|
+
local session="${1:-${CREWLY_SESSION_NAME:-}}"
|
|
23
|
+
[ -z "$session" ] && return 1
|
|
24
|
+
local teams_dir="${CREWLY_HOME}/teams"
|
|
25
|
+
[ ! -d "$teams_dir" ] && return 1
|
|
26
|
+
for config in "$teams_dir"/*/config.json; do
|
|
27
|
+
[ -f "$config" ] || continue
|
|
28
|
+
if [ "$(jq -r --arg s "$session" '.members[]? | select(.sessionName == $s) | "found"' "$config" 2>/dev/null | head -1)" = "found" ]; then
|
|
29
|
+
basename "$(dirname "$config")"
|
|
30
|
+
return 0
|
|
31
|
+
fi
|
|
32
|
+
done
|
|
33
|
+
return 1
|
|
34
|
+
}
|
|
35
|
+
if [ -z "$TEAM_ID" ]; then
|
|
36
|
+
TEAM_ID=$(resolve_team_id "$SESSION_NAME" || true)
|
|
37
|
+
fi
|
|
15
38
|
|
|
16
39
|
BODY=$(jq -n \
|
|
17
40
|
--arg context "$CONTEXT" \
|
|
18
41
|
--arg category "$CATEGORY" \
|
|
19
42
|
--arg role "$ROLE" \
|
|
43
|
+
--arg teamId "$TEAM_ID" \
|
|
20
44
|
'{context: $context} +
|
|
21
45
|
(if $category != "" then {category: $category} else {} end) +
|
|
22
|
-
(if $role != "" then {role: $role} else {} end)
|
|
46
|
+
(if $role != "" then {role: $role} else {} end) +
|
|
47
|
+
(if $teamId != "" then {teamId: $teamId} else {} end)')
|
|
23
48
|
|
|
24
49
|
api_call POST "/system/sops/query" "$BODY"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Get Team Norms
|
|
3
|
+
description: Read your team's norms (operating agreements — canDelegate, escalation, rules of engagement) relevant to the current moment.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: system
|
|
6
|
+
skillType: claude-skill
|
|
7
|
+
assignableRoles:
|
|
8
|
+
- developer
|
|
9
|
+
- qa
|
|
10
|
+
- tpm
|
|
11
|
+
- designer
|
|
12
|
+
- frontend-developer
|
|
13
|
+
- backend-developer
|
|
14
|
+
- fullstack-dev
|
|
15
|
+
- qa-engineer
|
|
16
|
+
- product-manager
|
|
17
|
+
- architect
|
|
18
|
+
- generalist
|
|
19
|
+
- team-leader
|
|
20
|
+
- sales
|
|
21
|
+
- support
|
|
22
|
+
triggers:
|
|
23
|
+
- get team norms
|
|
24
|
+
- team norms
|
|
25
|
+
- rules of engagement
|
|
26
|
+
- can i delegate
|
|
27
|
+
- escalation policy
|
|
28
|
+
tags:
|
|
29
|
+
- system
|
|
30
|
+
- norms
|
|
31
|
+
- governance
|
|
32
|
+
- team
|
|
33
|
+
execution:
|
|
34
|
+
type: script
|
|
35
|
+
script:
|
|
36
|
+
file: execute.sh
|
|
37
|
+
interpreter: bash
|
|
38
|
+
timeoutMs: 15000
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
# Get Team Norms
|
|
42
|
+
|
|
43
|
+
Read your **team norms** — the team's own operating agreement: who may delegate
|
|
44
|
+
to whom (`canDelegate`), role conventions, escalation paths, decision rights,
|
|
45
|
+
and rules of engagement. Norms are team-specific and authored by the team
|
|
46
|
+
(by the owner in the wiki, or proposed by agents via `update-team-norm`).
|
|
47
|
+
|
|
48
|
+
Norms differ from SOPs: a **SOP** is a reusable procedure ("how to do task X");
|
|
49
|
+
a **norm** is "how THIS team operates together." Consult norms before acting on
|
|
50
|
+
anything governance-related — delegating, escalating, deciding scope.
|
|
51
|
+
|
|
52
|
+
## Parameters
|
|
53
|
+
|
|
54
|
+
| Parameter | Required | Description |
|
|
55
|
+
|-----------|----------|-------------|
|
|
56
|
+
| `trigger` | No | Filter to norms relevant to a moment (e.g. `"before_commit"`, `"before_delegate"`). Omit to read all. |
|
|
57
|
+
| `teamId` | No | Team to read. Defaults to the team resolved from your `sessionName`. |
|
|
58
|
+
| `sessionName` | No | Your session name, used to resolve the team when `teamId` is omitted. |
|
|
59
|
+
|
|
60
|
+
## Example
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
bash config/skills/agent/core/get-team-norms/execute.sh '{"trigger":"before_delegate"}'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Output
|
|
67
|
+
|
|
68
|
+
JSON `{ success, count, data: [{ normId, title, trigger, content, updatedBy, updatedAt }] }`.
|
|
69
|
+
Returns an empty list if the team has no norms yet.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Update SOP
|
|
3
|
+
description: Author or update a custom SOP (a reusable procedure / playbook) for your team.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: system
|
|
6
|
+
skillType: claude-skill
|
|
7
|
+
assignableRoles:
|
|
8
|
+
- team-leader
|
|
9
|
+
- tpm
|
|
10
|
+
- product-manager
|
|
11
|
+
- architect
|
|
12
|
+
- generalist
|
|
13
|
+
- developer
|
|
14
|
+
- qa
|
|
15
|
+
- qa-engineer
|
|
16
|
+
- backend-developer
|
|
17
|
+
- frontend-developer
|
|
18
|
+
- fullstack-dev
|
|
19
|
+
triggers:
|
|
20
|
+
- update sop
|
|
21
|
+
- write a sop
|
|
22
|
+
- document the procedure
|
|
23
|
+
- create a playbook
|
|
24
|
+
- standardize how we
|
|
25
|
+
tags:
|
|
26
|
+
- system
|
|
27
|
+
- sops
|
|
28
|
+
- procedures
|
|
29
|
+
- team
|
|
30
|
+
execution:
|
|
31
|
+
type: script
|
|
32
|
+
script:
|
|
33
|
+
file: execute.sh
|
|
34
|
+
interpreter: bash
|
|
35
|
+
timeoutMs: 15000
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
# Update SOP
|
|
39
|
+
|
|
40
|
+
Create or update a **custom SOP** for your team — a reusable procedure /
|
|
41
|
+
playbook for *how to do a class of work* (e.g. "publishing an XHS post",
|
|
42
|
+
"running a release"). The SOP is written into the team's own SOP store
|
|
43
|
+
(`~/.crewly/teams/<id>/sops/`) and surfaces in the wiki under the team's
|
|
44
|
+
**SOPs** folder, alongside SOPs installed from the catalog. The owner can edit
|
|
45
|
+
it in the wiki UI.
|
|
46
|
+
|
|
47
|
+
Use this for durable, repeatable procedures — not one-off task notes (use the
|
|
48
|
+
wiki/memory) and not team governance rules (those are **team norms** — use
|
|
49
|
+
`update-team-norm`). Prefer installing an existing catalog SOP when one fits;
|
|
50
|
+
author a custom SOP only when the team needs something the catalog lacks.
|
|
51
|
+
|
|
52
|
+
## Parameters
|
|
53
|
+
|
|
54
|
+
| Parameter | Required | Description |
|
|
55
|
+
|-----------|----------|-------------|
|
|
56
|
+
| `sopId` | Yes | Stable kebab-case id / filename, e.g. `"xhs-posting"`. |
|
|
57
|
+
| `content` | Yes | The SOP body (markdown). The steps/procedure. |
|
|
58
|
+
| `title` | No | Human title, e.g. `"XHS Posting Checklist"`. Required when creating. |
|
|
59
|
+
| `category` | No | Optional sub-folder, e.g. `"common"`, `"marketing"`. |
|
|
60
|
+
| `append` | No | `"true"` to append to an existing SOP instead of overwriting. |
|
|
61
|
+
| `teamId` | No | Team to write to. Defaults to the team resolved from `sessionName`. |
|
|
62
|
+
| `sessionName` | No | Your session name, used to resolve the team when `teamId` is omitted. |
|
|
63
|
+
| `updatedBy` | No | Who authored the change (your agent/session name). |
|
|
64
|
+
|
|
65
|
+
## Example
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
bash config/skills/agent/core/update-sop/execute.sh '{"sopId":"xhs-posting","title":"XHS Posting Checklist","category":"marketing","content":"1. Draft hook.\n2. Add 3-5 tags.\n3. Post 7-9pm."}'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Output
|
|
72
|
+
|
|
73
|
+
JSON `{ success, action: "created" | "updated", sopId, title, category, path, relativePath }`.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Create or update a team's custom SOP.
|
|
3
|
+
# Writes to ~/.crewly/teams/{teamId}/sops/[{category}/]{sopId}.md
|
|
4
|
+
# (the per-team installed/custom SOP store the wiki surfaces under sop/).
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
source "${SCRIPT_DIR}/../../_common/lib.sh"
|
|
8
|
+
|
|
9
|
+
CREWLY_HOME="${HOME}/.crewly"
|
|
10
|
+
|
|
11
|
+
INPUT=$(read_json_input "${1:-}")
|
|
12
|
+
[ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"sopId\":\"xhs-posting\",\"title\":\"XHS Posting\",\"content\":\"...\",\"category\":\"common\"}'"
|
|
13
|
+
|
|
14
|
+
SOP_ID=$(printf '%s' "$INPUT" | jq -r '.sopId // empty')
|
|
15
|
+
TITLE=$(printf '%s' "$INPUT" | jq -r '.title // empty')
|
|
16
|
+
CATEGORY=$(printf '%s' "$INPUT" | jq -r '.category // empty')
|
|
17
|
+
CONTENT=$(printf '%s' "$INPUT" | jq -r '.content // empty')
|
|
18
|
+
APPEND=$(printf '%s' "$INPUT" | jq -r '.append // "false"')
|
|
19
|
+
TEAM_ID=$(printf '%s' "$INPUT" | jq -r '.teamId // empty')
|
|
20
|
+
SESSION_NAME=$(printf '%s' "$INPUT" | jq -r '.sessionName // empty')
|
|
21
|
+
UPDATED_BY=$(printf '%s' "$INPUT" | jq -r '.updatedBy // empty')
|
|
22
|
+
|
|
23
|
+
require_param "sopId" "$SOP_ID"
|
|
24
|
+
require_param "content" "$CONTENT"
|
|
25
|
+
|
|
26
|
+
# Sanitize id/category to safe path segments (no traversal, no slashes).
|
|
27
|
+
SOP_ID=$(printf '%s' "$SOP_ID" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9._-]/-/g; s/^-*//; s/-*$//')
|
|
28
|
+
CATEGORY=$(printf '%s' "$CATEGORY" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/-/g; s/^-*//; s/-*$//')
|
|
29
|
+
[ -z "$SOP_ID" ] && error_exit "sopId resolved to empty after sanitization"
|
|
30
|
+
|
|
31
|
+
# Resolve teamId: explicit param > lookup by sessionName > CREWLY_SESSION_NAME env
|
|
32
|
+
resolve_team_id() {
|
|
33
|
+
local session="${1:-${CREWLY_SESSION_NAME:-}}"
|
|
34
|
+
[ -z "$session" ] && return 1
|
|
35
|
+
local teams_dir="${CREWLY_HOME}/teams"
|
|
36
|
+
[ ! -d "$teams_dir" ] && return 1
|
|
37
|
+
for config in "$teams_dir"/*/config.json; do
|
|
38
|
+
[ -f "$config" ] || continue
|
|
39
|
+
local found
|
|
40
|
+
found=$(jq -r --arg s "$session" '.members[]? | select(.sessionName == $s) | "found"' "$config" 2>/dev/null | head -1)
|
|
41
|
+
if [ "$found" = "found" ]; then
|
|
42
|
+
basename "$(dirname "$config")"
|
|
43
|
+
return 0
|
|
44
|
+
fi
|
|
45
|
+
done
|
|
46
|
+
return 1
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if [ -z "$TEAM_ID" ]; then
|
|
50
|
+
TEAM_ID=$(resolve_team_id "$SESSION_NAME") || error_exit "Could not resolve teamId. Provide teamId or sessionName."
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
SOPS_DIR="${CREWLY_HOME}/teams/${TEAM_ID}/sops"
|
|
54
|
+
if [ -n "$CATEGORY" ]; then
|
|
55
|
+
SOPS_DIR="${SOPS_DIR}/${CATEGORY}"
|
|
56
|
+
REL_PATH="sop/${CATEGORY}/${SOP_ID}.md"
|
|
57
|
+
else
|
|
58
|
+
REL_PATH="sop/${SOP_ID}.md"
|
|
59
|
+
fi
|
|
60
|
+
mkdir -p "$SOPS_DIR"
|
|
61
|
+
|
|
62
|
+
SOP_FILE="${SOPS_DIR}/${SOP_ID}.md"
|
|
63
|
+
TODAY=$(date +%Y-%m-%d)
|
|
64
|
+
ACTION="created"
|
|
65
|
+
|
|
66
|
+
if [ -f "$SOP_FILE" ]; then
|
|
67
|
+
ACTION="updated"
|
|
68
|
+
EXISTING_TITLE=$(sed -n '/^---$/,/^---$/{ /^---$/d; s/^title: *//p; }' "$SOP_FILE" | head -1)
|
|
69
|
+
EXISTING_UPDATED_BY=$(sed -n '/^---$/,/^---$/{ /^---$/d; s/^updatedBy: *//p; }' "$SOP_FILE" | head -1)
|
|
70
|
+
[ -z "$TITLE" ] && TITLE="$EXISTING_TITLE"
|
|
71
|
+
[ -z "$UPDATED_BY" ] && UPDATED_BY="$EXISTING_UPDATED_BY"
|
|
72
|
+
|
|
73
|
+
if [ "$APPEND" = "true" ]; then
|
|
74
|
+
EXISTING_CONTENT=""
|
|
75
|
+
FM_DONE=false
|
|
76
|
+
FM_COUNT=0
|
|
77
|
+
while IFS= read -r line || [ -n "$line" ]; do
|
|
78
|
+
if [ "$line" = "---" ]; then
|
|
79
|
+
FM_COUNT=$((FM_COUNT + 1))
|
|
80
|
+
if [ "$FM_COUNT" -ge 2 ]; then
|
|
81
|
+
FM_DONE=true
|
|
82
|
+
continue
|
|
83
|
+
fi
|
|
84
|
+
elif [ "$FM_DONE" = true ]; then
|
|
85
|
+
EXISTING_CONTENT="${EXISTING_CONTENT}${line}
|
|
86
|
+
"
|
|
87
|
+
fi
|
|
88
|
+
done < "$SOP_FILE"
|
|
89
|
+
EXISTING_CONTENT=$(echo "$EXISTING_CONTENT" | sed '/./,$!d')
|
|
90
|
+
CONTENT="${EXISTING_CONTENT}
|
|
91
|
+
${CONTENT}"
|
|
92
|
+
fi
|
|
93
|
+
else
|
|
94
|
+
[ -z "$TITLE" ] && error_exit "title is required when creating a new SOP"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
{
|
|
98
|
+
echo "---"
|
|
99
|
+
echo "title: ${TITLE}"
|
|
100
|
+
[ -n "$CATEGORY" ] && echo "category: ${CATEGORY}"
|
|
101
|
+
[ -n "$UPDATED_BY" ] && echo "updatedBy: ${UPDATED_BY}"
|
|
102
|
+
echo "updatedAt: ${TODAY}"
|
|
103
|
+
echo "---"
|
|
104
|
+
echo ""
|
|
105
|
+
echo "$CONTENT"
|
|
106
|
+
} > "$SOP_FILE"
|
|
107
|
+
|
|
108
|
+
jq -n \
|
|
109
|
+
--arg sopId "$SOP_ID" \
|
|
110
|
+
--arg title "$TITLE" \
|
|
111
|
+
--arg category "$CATEGORY" \
|
|
112
|
+
--arg action "$ACTION" \
|
|
113
|
+
--arg path "$SOP_FILE" \
|
|
114
|
+
--arg relativePath "$REL_PATH" \
|
|
115
|
+
'{success: true, action: $action, sopId: $sopId, title: $title, category: $category, path: $path, relativePath: $relativePath}'
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Update Team Norm
|
|
3
|
+
description: Propose or update a team norm (an operating agreement — canDelegate, escalation, rules of engagement) for your team.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: system
|
|
6
|
+
skillType: claude-skill
|
|
7
|
+
assignableRoles:
|
|
8
|
+
- team-leader
|
|
9
|
+
- tpm
|
|
10
|
+
- product-manager
|
|
11
|
+
- architect
|
|
12
|
+
- generalist
|
|
13
|
+
- developer
|
|
14
|
+
- qa
|
|
15
|
+
triggers:
|
|
16
|
+
- update team norm
|
|
17
|
+
- propose a norm
|
|
18
|
+
- set a team rule
|
|
19
|
+
- we should always
|
|
20
|
+
- going forward the team should
|
|
21
|
+
tags:
|
|
22
|
+
- system
|
|
23
|
+
- norms
|
|
24
|
+
- governance
|
|
25
|
+
- team
|
|
26
|
+
execution:
|
|
27
|
+
type: script
|
|
28
|
+
script:
|
|
29
|
+
file: execute.sh
|
|
30
|
+
interpreter: bash
|
|
31
|
+
timeoutMs: 15000
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
# Update Team Norm
|
|
35
|
+
|
|
36
|
+
Create or update a **team norm** — a durable operating agreement for your team
|
|
37
|
+
(who may delegate to whom, escalation paths, decision rights, rules of
|
|
38
|
+
engagement, recurring conventions). Use this when a lasting team-wide rule
|
|
39
|
+
emerges that future work should follow — not for one-off task notes (use the
|
|
40
|
+
wiki/memory for those) and not for reusable procedures (those are SOPs).
|
|
41
|
+
|
|
42
|
+
Norms you write land in the team's norm store and surface in the wiki under the
|
|
43
|
+
team's **Team Norms** folder, where the owner can review and edit them. Treat
|
|
44
|
+
this as *proposing* a norm: keep it concise, state the rule and when it applies.
|
|
45
|
+
|
|
46
|
+
## Parameters
|
|
47
|
+
|
|
48
|
+
| Parameter | Required | Description |
|
|
49
|
+
|-----------|----------|-------------|
|
|
50
|
+
| `normId` | Yes | Stable kebab-case id / filename, e.g. `"code-commit"`, `"delegation"`. |
|
|
51
|
+
| `content` | Yes | The norm body (markdown). State the rule and its rationale. |
|
|
52
|
+
| `title` | No | Human title, e.g. `"Code Commit Norm"`. |
|
|
53
|
+
| `trigger` | No | When this norm applies, e.g. `"before_commit"`, `"before_delegate"`. |
|
|
54
|
+
| `append` | No | `"true"` to append to an existing norm instead of overwriting. |
|
|
55
|
+
| `teamId` | No | Team to write to. Defaults to the team resolved from `sessionName`. |
|
|
56
|
+
| `sessionName` | No | Your session name, used to resolve the team when `teamId` is omitted. |
|
|
57
|
+
| `updatedBy` | No | Who authored the change (your agent/session name). |
|
|
58
|
+
|
|
59
|
+
## Example
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
bash config/skills/agent/core/update-team-norm/execute.sh '{"normId":"delegation","title":"Delegation","trigger":"before_delegate","content":"Leads may delegate to their own team only; cross-team work goes through the orchestrator."}'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Output
|
|
66
|
+
|
|
67
|
+
JSON `{ success, action: "created" | "updated", normId, path }`.
|