@damian87/omp 0.2.0 → 0.4.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/.github/skills/weighted-consensus/SKILL.md +120 -0
- package/README.md +59 -1
- package/catalog/capabilities.json +46 -0
- package/catalog/skills-general.json +29 -1
- package/dist/src/cli.d.ts +8 -0
- package/dist/src/cli.js +147 -3
- package/dist/src/cli.js.map +1 -1
- package/dist/src/council/config.d.ts +32 -0
- package/dist/src/council/config.js +84 -0
- package/dist/src/council/config.js.map +1 -0
- package/dist/src/council/engine.d.ts +19 -0
- package/dist/src/council/engine.js +193 -0
- package/dist/src/council/engine.js.map +1 -0
- package/dist/src/council/index.d.ts +20 -0
- package/dist/src/council/index.js +72 -0
- package/dist/src/council/index.js.map +1 -0
- package/dist/src/council/prompts.d.ts +32 -0
- package/dist/src/council/prompts.js +173 -0
- package/dist/src/council/prompts.js.map +1 -0
- package/dist/src/council/synth.d.ts +15 -0
- package/dist/src/council/synth.js +57 -0
- package/dist/src/council/synth.js.map +1 -0
- package/dist/src/council/types.d.ts +96 -0
- package/dist/src/council/types.js +4 -0
- package/dist/src/council/types.js.map +1 -0
- package/dist/src/mode-state/paths.d.ts +6 -0
- package/dist/src/mode-state/paths.js +12 -0
- package/dist/src/mode-state/paths.js.map +1 -1
- package/dist/src/team/api.d.ts +60 -1
- package/dist/src/team/api.js +101 -0
- package/dist/src/team/api.js.map +1 -1
- package/dist/src/team/config.d.ts +7 -0
- package/dist/src/team/config.js +16 -0
- package/dist/src/team/config.js.map +1 -0
- package/dist/src/team/mailbox.d.ts +30 -0
- package/dist/src/team/mailbox.js +188 -0
- package/dist/src/team/mailbox.js.map +1 -0
- package/dist/src/team/runtime.d.ts +9 -1
- package/dist/src/team/runtime.js +18 -12
- package/dist/src/team/runtime.js.map +1 -1
- package/dist/src/team/types.d.ts +25 -0
- package/dist/src/team/worker-bootstrap.js +29 -0
- package/dist/src/team/worker-bootstrap.js.map +1 -1
- package/dist/test/catalog.test.d.ts +1 -0
- package/dist/test/catalog.test.js +21 -0
- package/dist/test/catalog.test.js.map +1 -0
- package/dist/test/jira.test.d.ts +1 -0
- package/dist/test/jira.test.js +26 -0
- package/dist/test/jira.test.js.map +1 -0
- package/dist/test/lint.test.d.ts +1 -0
- package/dist/test/lint.test.js +9 -0
- package/dist/test/lint.test.js.map +1 -0
- package/dist/test/sync.test.d.ts +1 -0
- package/dist/test/sync.test.js +15 -0
- package/dist/test/sync.test.js.map +1 -0
- package/docs/plans/2026-05-29-team-messaging-and-nudge-gating-design.md +170 -0
- package/package.json +1 -1
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Design: Team messaging (worker↔worker / worker↔leader) + nudge gating
|
|
2
|
+
|
|
3
|
+
> Status: **Design only — no implementation yet.** Target repo: `oh-my-copilot`.
|
|
4
|
+
> Date: 2026-05-29
|
|
5
|
+
|
|
6
|
+
## 1. Problem & evidence
|
|
7
|
+
|
|
8
|
+
Two related gaps in `src/team`:
|
|
9
|
+
|
|
10
|
+
**A. Workers cannot message anyone.** The entire `team api` surface (`src/cli.ts:35`) is:
|
|
11
|
+
|
|
12
|
+
- `team api claim-task`
|
|
13
|
+
- `team api transition-task-status`
|
|
14
|
+
|
|
15
|
+
There is **no `send-message`, `broadcast`, or mailbox** anywhere in `src`. The only
|
|
16
|
+
worker→lead signal is an outbox line auto-appended on task transition
|
|
17
|
+
(`src/team/api.ts:55-65`), consumed by the monitor (`readNewOutbox`). So a worker
|
|
18
|
+
cannot ask the lead a question, hand off to a peer, or nudge a teammate. This is the
|
|
19
|
+
"teams says limitation can't message" behavior.
|
|
20
|
+
|
|
21
|
+
This must work **without MCP** (Copilot CLI; MCP is disabled in the target org). The
|
|
22
|
+
existing design is already file + CLI based, so this is the natural fit.
|
|
23
|
+
|
|
24
|
+
**B. Nudge is ungated.** `NudgeTracker` runs only inside `monitorTeam`
|
|
25
|
+
(`src/team/runtime.ts:224`) and is **default-on** (`:213`). `monitorTeam` is not yet
|
|
26
|
+
wired into any command, so nudge effectively never fires today — but when it is wired
|
|
27
|
+
in, default-on would nudge every monitored team run (including read-only polling).
|
|
28
|
+
Desired: **off by default, but ON for `/team` orchestration runs and for active
|
|
29
|
+
ralph/loop modes.** Plain read-only polling (`team status`) and library/one-shot use
|
|
30
|
+
stay quiet.
|
|
31
|
+
|
|
32
|
+
## 2. What already exists (reuse, don't rebuild)
|
|
33
|
+
|
|
34
|
+
- `state-paths.ts` already defines `mailboxDir` (`.omp/state/team/<team>/mailbox`) and
|
|
35
|
+
`dispatchDir`, and `ensureTeamDirs` already creates them. Workers already have
|
|
36
|
+
`inboxFile` (`workers/<name>/inbox.md`), `outboxFile`, `heartbeatFile`, pane id in
|
|
37
|
+
config (`Worker.paneId`).
|
|
38
|
+
- `tmux.ts` exposes `sendToWorker(api, paneId, text, …)` — the nudge transport.
|
|
39
|
+
- `outbox.ts` has a robust byte-cursor JSONL reader we can mirror for mailbox reads.
|
|
40
|
+
|
|
41
|
+
## 3. Feature A — messaging
|
|
42
|
+
|
|
43
|
+
### 3.1 Data model
|
|
44
|
+
|
|
45
|
+
New file `src/team/mailbox.ts`. One JSONL file per recipient:
|
|
46
|
+
`.omp/state/team/<team>/mailbox/<recipient>.jsonl`, plus a `.<recipient>.offset` cursor
|
|
47
|
+
(mirror `outbox.ts`). `leader` is the reserved recipient name for the lead.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
export interface MailboxMessage {
|
|
51
|
+
id: string; // uuid
|
|
52
|
+
from: string; // worker name or "leader"
|
|
53
|
+
to: string; // worker name or "leader"
|
|
54
|
+
body: string;
|
|
55
|
+
timestamp: string; // ISO
|
|
56
|
+
deliveredAt?: string;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Functions: `appendMailbox`, `readNewMailbox`/`peekMailbox` (cursor-based),
|
|
61
|
+
`listMailbox`, `markDelivered`.
|
|
62
|
+
|
|
63
|
+
### 3.2 API surface (additions to `src/team/api.ts` + `cli.ts`)
|
|
64
|
+
|
|
65
|
+
- `team api send-message --input '{team_name, from, to, body, cwd?}'`
|
|
66
|
+
→ validates `to` is `leader` or a registered worker (`config.workers`), rejects
|
|
67
|
+
unknown recipients with `unknown_recipient` (no phantom mailbox), appends to the
|
|
68
|
+
recipient mailbox, then **nudges the recipient pane** (see 3.3).
|
|
69
|
+
- `team api broadcast --input '{team_name, from, body, cwd?}'`
|
|
70
|
+
→ fans out to **every worker except `from`, PLUS the `leader` mailbox**.
|
|
71
|
+
Reuses oh-my-claudecode's mechanism (`teamBroadcast`, `team-ops.ts:604`: loop
|
|
72
|
+
recipients → `send` to each), but oh-my-claudecode skips the lead (it only iterates
|
|
73
|
+
`cfg.workers`); here we additionally append `leader` to the recipient set so the lead
|
|
74
|
+
receives broadcasts too. Sender is always excluded (no self-message, no echo loop).
|
|
75
|
+
- `team api mailbox-list --input '{team_name, worker, cwd?}'` → list (optionally
|
|
76
|
+
undelivered only).
|
|
77
|
+
- `team api mailbox-mark-delivered --input '{team_name, worker, message_id, cwd?}'`.
|
|
78
|
+
|
|
79
|
+
All pure file ops, callable directly in tests (no MCP, no tmux required for persistence).
|
|
80
|
+
|
|
81
|
+
### 3.3 Delivery / nudge
|
|
82
|
+
|
|
83
|
+
After persisting, look up the recipient's `paneId` from `config.workers` (or
|
|
84
|
+
`leader_pane_id` in config). If present and a tmux session is live, call
|
|
85
|
+
`sendToWorker(...)` with a short trigger. If no pane (worker not spawned / headless
|
|
86
|
+
test), persistence still succeeds — delivery is pull-based via `mailbox-list`.
|
|
87
|
+
**Nudge-on-send reuses the same `sendToWorker` transport, independent of the
|
|
88
|
+
idle-`NudgeTracker`.**
|
|
89
|
+
|
|
90
|
+
**Throttle/coalesce — reuse what already exists, build nothing new:**
|
|
91
|
+
- The idle `NudgeTracker` (`idle-nudge.ts`) already carries the same throttle as
|
|
92
|
+
oh-my-claudecode (`scanIntervalMs: 5000`, `maxCount: 3`) — unchanged.
|
|
93
|
+
- For send-nudge, mirror oh-my-claudecode's `generateMailboxTriggerMessage(count)`:
|
|
94
|
+
the trigger states the **unread count** (`listMailbox(...).filter(!deliveredAt).length`)
|
|
95
|
+
— "N new msg(s): read your mailbox …". Multiple messages arriving before the worker
|
|
96
|
+
reads simply raise the count in the next poke rather than spamming distinct triggers.
|
|
97
|
+
No separate coalescing/debounce machinery.
|
|
98
|
+
|
|
99
|
+
### 3.4 Worker overlay (`worker-bootstrap.ts buildInboxMarkdown`)
|
|
100
|
+
|
|
101
|
+
Add a "Messaging" section teaching workers they may message the **lead OR any teammate**:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
omp team api send-message --input '{"team_name":…,"from":"<me>","to":"leader","body":"…"}' --json
|
|
105
|
+
omp team api send-message --input '{"team_name":…,"from":"<me>","to":"<teammate>","body":"…"}' --json
|
|
106
|
+
omp team api mailbox-list --input '{"team_name":…,"worker":"<me>"}' --json
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
State that the recipient is auto-nudged, and that unknown names return `unknown_recipient`.
|
|
110
|
+
|
|
111
|
+
### 3.5 Tests (Vitest, file-based, no MCP)
|
|
112
|
+
|
|
113
|
+
`test/team/mailbox.test.ts` + `test/team/api.messaging.test.ts`:
|
|
114
|
+
worker→leader, worker→peer, broadcast-excludes-sender, mailbox-list/mark-delivered,
|
|
115
|
+
unknown-recipient rejection, cursor advance. A nudge unit test mocks `tmux`/`sendToWorker`
|
|
116
|
+
to assert the recipient pane is poked.
|
|
117
|
+
|
|
118
|
+
## 4. Feature B — nudge gating
|
|
119
|
+
|
|
120
|
+
Change `monitorTeam` so nudge is **off by default**, but **ON for `/team`
|
|
121
|
+
orchestration runs and active ralph/loop modes**:
|
|
122
|
+
|
|
123
|
+
- Default `opts.nudge?.enabled` to **`false`** (flip current `!== false`).
|
|
124
|
+
- Add `resolveNudgeEnabled(opts, cwd)` → `true` when ANY of:
|
|
125
|
+
1. `opts.nudge?.enabled === true` — set by the **`/team` command's monitor loop**
|
|
126
|
+
(the orchestration spawn+monitor path in `cli.ts` passes `nudge:{enabled:true}`).
|
|
127
|
+
This is what makes nudge ON for `/team`.
|
|
128
|
+
2. A loop-mode state file is active: `readRalph(cwd)?.active`, or the equivalent
|
|
129
|
+
`ultrawork`/`ultraqa` state (modes live at `.omp/state/<mode>.json`,
|
|
130
|
+
`src/mode-state/paths.ts`).
|
|
131
|
+
3. Falls back to `false` otherwise.
|
|
132
|
+
- Add a small `isLoopModeActive(cwd)` helper in `mode-state` (reads the three mode
|
|
133
|
+
files) so condition 2 is one source of truth.
|
|
134
|
+
|
|
135
|
+
Result:
|
|
136
|
+
- **`/team` orchestration** → nudge ON (condition 1).
|
|
137
|
+
- **ralph / ultrawork / ultraqa loops** → nudge ON (condition 2).
|
|
138
|
+
- **Read-only `team status` / library one-shot use** → nudge OFF (no `enabled:true`,
|
|
139
|
+
no active loop mode).
|
|
140
|
+
|
|
141
|
+
### Tests
|
|
142
|
+
|
|
143
|
+
`test/team/runtime.test.ts` additions: nudge off by default; ON when `enabled:true`
|
|
144
|
+
(the `/team` path); ON when a ralph/loop mode state is active; OFF when neither signal
|
|
145
|
+
is present (e.g. `team status` polling).
|
|
146
|
+
|
|
147
|
+
## 5. Build sequence
|
|
148
|
+
|
|
149
|
+
1. `mailbox.ts` + tests (red→green).
|
|
150
|
+
2. `api.ts` messaging fns + `cli.ts` wiring + tests.
|
|
151
|
+
3. `worker-bootstrap.ts` overlay docs + test.
|
|
152
|
+
4. Nudge gating in `runtime.ts` + `mode-state` helper + tests.
|
|
153
|
+
5. Update `.github/skills/team/SKILL.md` to document messaging + nudge gating.
|
|
154
|
+
|
|
155
|
+
## 6. Out of scope (YAGNI)
|
|
156
|
+
|
|
157
|
+
- No dispatch-queue/retry state machine (the richer oh-my-claudecode design) — pull-based
|
|
158
|
+
mailbox + best-effort nudge is enough here.
|
|
159
|
+
- No leader registered as a team member; `leader` stays a reserved mailbox name.
|
|
160
|
+
- No cross-team messaging.
|
|
161
|
+
|
|
162
|
+
## 7. Resolved decisions
|
|
163
|
+
|
|
164
|
+
- **Broadcast reaches workers AND the lead** (every worker except sender + the `leader`
|
|
165
|
+
mailbox). Extends oh-my-claudecode's workers-only `teamBroadcast`.
|
|
166
|
+
- **Nudge throttling reuses existing mechanisms** (idle `NudgeTracker` scan/maxCount +
|
|
167
|
+
an unread-count in the send trigger, mirroring `generateMailboxTriggerMessage`).
|
|
168
|
+
No new debounce/coalesce layer.
|
|
169
|
+
- **Nudge gating:** off by default; ON for `/team` orchestration runs and active
|
|
170
|
+
ralph/ultrawork/ultraqa loop modes.
|