@rallycry/conveyor-skills 0.1.3 → 1.0.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/README.md +19 -5
- package/package.json +1 -1
- package/skills/conveyor-build/SKILL.md +262 -0
- package/skills/conveyor-build/references/pack-path.md +224 -0
- package/skills/conveyor-build/references/task-path.md +67 -0
- package/skills/conveyor-consensus/SKILL.md +99 -0
- package/skills/conveyor-consensus/references/doc-template.html +204 -0
- package/skills/conveyor-local-loop/SKILL.md +34 -41
- package/skills/conveyor-meeting-review/SKILL.md +72 -0
- package/skills/conveyor-plan/SKILL.md +85 -12
- package/skills/conveyor-plan/references/plan-format.md +82 -5
- package/skills/conveyor-review/SKILL.md +161 -0
- package/skills/conveyor-start/SKILL.md +106 -0
- package/skills/conveyor-triage/SKILL.md +174 -0
- package/skills/conveyor-workflows/SKILL.md +34 -8
- package/skills/conveyor-local-pack/SKILL.md +0 -223
- package/skills/conveyor-local-task/SKILL.md +0 -92
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: conveyor-consensus
|
|
3
|
+
description: Sweep everything a Conveyor project is connected to — work channels, cards, tags, meetings, Drive, logs, analytics, the repo — count what actually happened, score the proposals on the table against those counts, and ship an HTML verdict onto the card. Use when the user says "/conveyor-consensus <question>", "get us to consensus on X", "what are people actually complaining about", "does this plan hit the pain", "score these proposals", or when a new stakeholder proposal lands mid-thread and needs scoring against the evidence. Discovers its sources at runtime, so it runs the same in a pod and in a local MCP session.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Conveyor Consensus
|
|
7
|
+
|
|
8
|
+
The genre: **an uninterested observer pulls every relevant source, counts what actually happened, scores what people are proposing against those counts, and ships a doc the team can converge on.** The deliverable is a verdict with receipts, not a summary.
|
|
9
|
+
|
|
10
|
+
## The stance
|
|
11
|
+
|
|
12
|
+
- Write as the outside party with no stake. Verdicts, not summaries: "covered / partial / missed", "possible / not possible by design", "this suggestion doesn't solve anything, here's why."
|
|
13
|
+
- Every claim carries a count and a receipt (card link, permalink, PR link, quote with author + date). Approximate tallies are fine when labeled as such; fabricated precision is not.
|
|
14
|
+
- The evidence outranks the proposals: score proposals against the data, never the other way around.
|
|
15
|
+
- Counter-analysis is part of the job. When a stakeholder idea doesn't survive the data, say so plainly, show the receipt that kills it, and name the nearest thing that does work.
|
|
16
|
+
|
|
17
|
+
## Phase 0: discover what this project actually has
|
|
18
|
+
|
|
19
|
+
**Do this before planning the sweep.** Which sources exist is a per-project fact, not a constant, and guessing wrong wastes a phase either way — assuming a channel that isn't registered, or skipping a Drive that is.
|
|
20
|
+
|
|
21
|
+
1. `get_connection_context` — who and where. Same call in a pod and a local MCP session; it reports the card in a pod and the account/board in an MCP client.
|
|
22
|
+
2. `list_project_integrations` — which of repository, Slack/Discord, email, GCP, Grafana, Google Analytics, Drive, Cloudflare, incidents are configured, plus the registered work channels. Credential-free booleans; this is the map.
|
|
23
|
+
3. `list_project_channels` — the channels an admin registered as agent-reachable, each with a description of what happens there. **The description is the routing signal**: it is how you tell the channel where support complaints land from the one where releases are announced. Only registered channels are reachable at all; an unregistered channel does not exist for this skill regardless of what the bot can see.
|
|
24
|
+
4. **ToolSearch for the optional surfaces** rather than assuming them: `drive_*`, meeting tools, `query_gcp_logs` / `query_grafana_logs`, `get_analytics_summary`. Also probe for supplemental local MCPs the user may have connected — a user-token Slack MCP is the notable one, because it enables true keyword search that Conveyor's own tools cannot do (see the Slack search note below).
|
|
25
|
+
|
|
26
|
+
Announce a one-line plan naming the sources you found, then sweep. **Say what you did not find**, too: "no Drive, no meetings, no Grafana on this project" is information the reader needs to weigh the verdict.
|
|
27
|
+
|
|
28
|
+
## Phase 1: sweep every spot that exists
|
|
29
|
+
|
|
30
|
+
| Source | How |
|
|
31
|
+
| ------ | --- |
|
|
32
|
+
| Work channels | `read_channel_messages` per registered readable channel, paging back with `olderCursor` until the window covers the question. `authorIsBot` separates the team's discussion from Conveyor's own card feed — check it before treating a message as a teammate's. Read thread replies (`threadTs`) where a thread carries the argument. |
|
|
33
|
+
| Conveyor cards | `search_tasks` with ALL `typeFilters` (task, incident, suggestion) and several keyword variants — the term, the term plus symptom words, the adjacent nouns people actually use. Incidents carry fingerprint dedup, so an incident's upvote count is itself a frequency signal. Check whether a decision card already exists; the doc is usually its input. |
|
|
34
|
+
| Tags | `list_tags` then `get_tag` on the relevant ones — the overview is the project's own domain vocabulary, and it names the subsystems your categories should line up with. |
|
|
35
|
+
| Card chat | `read_task_chat` on the cards the search surfaced. The argument usually lives in the chat, not the description. |
|
|
36
|
+
| Meetings | If the meeting tools exist, list and read the ones in the window. A transcript is the densest source of "what people actually said" you will find. |
|
|
37
|
+
| Drive | `drive_list_files` + `drive_read_file` when the project has a folder — specs, retros, and operational sheets live there. A spreadsheet's columns are the incumbent data model and its stalest rows are the pain. |
|
|
38
|
+
| Logs | `query_gcp_logs` / `query_grafana_logs` when the question is about failures rather than opinions. A frequency count from logs outranks any recollection of how often something breaks. |
|
|
39
|
+
| Analytics | `get_analytics_summary` when the question touches traffic, adoption, or "did anyone use it". |
|
|
40
|
+
| Repo | Prior-art check: has someone already built or started this? `rg`, `git log`, branches, the knowledge graph when present. **A negative result — "no trace of X in the codebase" — is a finding worth printing.** |
|
|
41
|
+
| Vendor / product docs | Try `https://<docs-host>/llms.txt` first; many doc sites ship a full index. Verify every "possible / impossible" ruling against a primary page fetched THIS session and link it. Vendors often have more than one API surface (legacy + current); check both before ruling a capability gap. |
|
|
42
|
+
|
|
43
|
+
**Slack keyword search is not available to this skill.** `search.messages` requires a USER token; Conveyor's bot cannot call it. `read_channel_messages` is history paging, not search. So either page the relevant channels and filter model-side, or — when the user has a personal Slack MCP connected — use that for search and say so. **The method footnote must state which mode ran**, because "I read the last 300 messages in two channels" and "I searched the workspace" are different evidence bases and a reader deserves to know which one is behind the counts.
|
|
44
|
+
|
|
45
|
+
Sweep hygiene:
|
|
46
|
+
|
|
47
|
+
- **Delegate bulk sweeps to a subagent** so oversized pages never enter the main thread. Give it the exact queries, pagination instructions, the tool-loading line, and a strict deliverable spec: categorized findings with counts, sources, a few dated example incidents each with a link, a raw-coverage note (queries run, volume reviewed, date range, dominant sources), and a surprises section. Cap the report length.
|
|
48
|
+
- Record who reported each incident and when. Attribution splits ("their side vs ours", "process vs code defect") and time windows ("only since <month>") are the follow-up questions every single time; keep the underlying dated list so re-slicing is cheap.
|
|
49
|
+
|
|
50
|
+
## Phase 2: analysis
|
|
51
|
+
|
|
52
|
+
1. **Bin the evidence into named categories** with incident tallies — not message counts; one saga is one incident. Rank by frequency. Pull a few verbatim quotes that carry the tone, each with author, source, and date.
|
|
53
|
+
2. **Capability map** when a vendor or tool is involved: their surface versus our wants, item by item, each with a link.
|
|
54
|
+
3. **Score every stakeholder proposal** against the FULL category list: COVERED / PARTIAL (symptom yes, root cause no) / MISSED, with one sentence of why each. Score proposals separately, then head-to-head.
|
|
55
|
+
4. **Verify the ambitious claims.** Any proposal line hinging on "the API can (or can't) do X" gets a primary-source check before scoring — these checks regularly flip verdicts.
|
|
56
|
+
5. **Build the merged plan**: the union of the proposals plus the gaps nobody wrote down, every line carrying a feasibility ruling — supported by the vendor (with the doc link), configuration not code, our build, or not possible (say why, and whether the impossibility is actually desirable).
|
|
57
|
+
6. **Separate policy decisions from features.** Some open items are rulings only humans can make; flag them explicitly rather than designing around them silently.
|
|
58
|
+
|
|
59
|
+
## Phase 3: the doc
|
|
60
|
+
|
|
61
|
+
Build from `references/doc-template.html` — a working skeleton with three-state theme tokens, a div bar chart, stacked scoreboards, verdict-chip tables, quote blocks, and a method footnote already styled. In a local session, load `artifact-design` and `dataviz` first; in a pod those skills are absent, and the template carries enough of their decisions to stand alone.
|
|
62
|
+
|
|
63
|
+
**The template is self-contained on purpose and must stay that way.** The report is served from the API under a sandbox CSP (`sandbox; default-src 'none'; style-src 'unsafe-inline'; img-src data:`), which blocks external stylesheets, webfonts, scripts, and remote images. A JS charting library cannot run; a linked font fails silently and the doc renders in a fallback face with no error. Inline CSS, div/CSS charts, and `data:` URIs only.
|
|
64
|
+
|
|
65
|
+
Doc anatomy (drop sections that don't apply, keep the order):
|
|
66
|
+
|
|
67
|
+
1. **Eyebrow + name + dek + meta line** — corpus size, date range, source count, what decision it feeds.
|
|
68
|
+
2. **TL;DR box** — the verdict in 2-3 bold-led paragraphs. A reader who stops here can act.
|
|
69
|
+
3. **The evidence** — frequency bar chart (single hue, direct value labels), a note naming dominant sources, then the tone quotes.
|
|
70
|
+
4. **What already exists** — incumbent systems and prior art, including negative results.
|
|
71
|
+
5. **Proposal scorecards** — one chip table per proposal, then a head-to-head stacked scoreboard including a "merged" row; it sells the synthesis.
|
|
72
|
+
6. **The merged plan** with per-item feasibility chips and links.
|
|
73
|
+
7. **The two cents** — a handful of numbered recommendations, each an argument, not a platitude.
|
|
74
|
+
8. **Method footnote** — queries, counts, date range, which channels were paged versus searched, what was verified against primary sources, and **what was not done**.
|
|
75
|
+
|
|
76
|
+
Chart rules that repeatedly matter: plain div/CSS charts over JS; one strong chart beats two mushy ones; never chart numbers you had to invent — a chip list or prose with "~" beats a fake-precise graph; status chips always carry text, never colour alone.
|
|
77
|
+
|
|
78
|
+
## Phase 4: ship it onto the card
|
|
79
|
+
|
|
80
|
+
1. **`upload_attachment`** with the HTML file — title it with the question, so the card's attachment list reads as a question rather than a filename. This is the required path and the only one that works in a pod.
|
|
81
|
+
2. **Post the verdict to card chat**: the returned link plus a three-bullet summary. Someone scanning the card should get the answer without opening the report.
|
|
82
|
+
3. **When the ask was "align the channel"**, post the summary and link into the relevant work channel with `post_channel_message` — but only into a channel whose registration grants posting, and only when the user asked for that. A consensus doc arriving unbidden in a team's channel is a different act from one attached to a card.
|
|
83
|
+
4. **Local sessions may also publish an Artifact** for a shareable URL, and `SendUserFile` the HTML — both are additive. In a pod neither exists; the attachment is the deliverable.
|
|
84
|
+
5. **Revisions re-upload to the SAME card.** The doc is living; never fork it into `report-v2.html`.
|
|
85
|
+
|
|
86
|
+
## Phase 5: the consensus loop
|
|
87
|
+
|
|
88
|
+
The doc is the midpoint, not the end. Expect and serve:
|
|
89
|
+
|
|
90
|
+
- **Follow-up slices**: "table of every incident with details", "only this quarter", "how many were X versus Y", "day-by-day with what would have prevented it". Answer from the kept evidence list; fold into the doc only what changes a verdict.
|
|
91
|
+
- **Proposal reactions**: score new and revised proposals as they land, including negatively, with receipts, and re-upload.
|
|
92
|
+
|
|
93
|
+
## Environment honesty
|
|
94
|
+
|
|
95
|
+
State degradations in the method footnote rather than skipping them silently:
|
|
96
|
+
|
|
97
|
+
- **No WebSearch/WebFetch in a pod** — vendor-doc claims cannot be verified against primary sources there. Print "not verified against primary docs" on the affected lines instead of dropping the check quietly.
|
|
98
|
+
- **No registered work channels** — say so. It usually means the team's discussion is somewhere this skill cannot see, which is the single most important caveat a reader can have.
|
|
99
|
+
- **Bot-visible history only** — the bot reads channels it was invited to. A channel the team talks in but never invited the bot to is invisible, and that absence does not show up as an error anywhere.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
<!-- Consensus doc skeleton. Proven treatment: observer-memo, banker-blue accent.
|
|
2
|
+
Swap palette/type ONLY if the subject demands a different identity.
|
|
3
|
+
Replace every UPPERCASE placeholder. Delete sections that don't apply; keep the order.
|
|
4
|
+
|
|
5
|
+
SELF-CONTAINED ON PURPOSE — do not add external references.
|
|
6
|
+
This file is uploaded to a card and served by the API under a sandbox CSP
|
|
7
|
+
("sandbox; default-src 'none'; style-src 'unsafe-inline'; img-src data:").
|
|
8
|
+
That blocks webfont stylesheets, external CSS/JS, and remote images. The
|
|
9
|
+
upstream grimoire template linked Google Fonts; it is replaced here with a
|
|
10
|
+
system stack, because under this CSP the link fails silently and the doc
|
|
11
|
+
renders in a fallback font with no error. Same rule for charts: the div/CSS
|
|
12
|
+
bars below work, a JS charting library cannot run at all.
|
|
13
|
+
|
|
14
|
+
Images, if you truly need one, must be data: URIs. -->
|
|
15
|
+
<title>DOC NAME</title>
|
|
16
|
+
<style>
|
|
17
|
+
:root {
|
|
18
|
+
--bg: #f7f9fb; --surface: #ffffff;
|
|
19
|
+
--ink: #16222e; --ink-2: #48596a; --ink-3: #74838f;
|
|
20
|
+
--line: #d9e0e7; --line-soft: #e8edf1;
|
|
21
|
+
--accent: #20618f; --accent-soft: #dcebf5;
|
|
22
|
+
--bar: #2e6f9e; --bar-hover: #20618f;
|
|
23
|
+
--good-ink: #176a44; --good-bg: #ddf0e5;
|
|
24
|
+
--warn-ink: #8a5d00; --warn-bg: #f6ecd2;
|
|
25
|
+
--miss-ink: #a13529; --miss-bg: #f9e2de;
|
|
26
|
+
--neutral-ink: #55606b; --neutral-bg: #e8ecf0;
|
|
27
|
+
--quote-rail: #c3d5e2;
|
|
28
|
+
}
|
|
29
|
+
/* Three-state theming: bare :root = light; media block guarded against explicit light; data-theme block wins for the toggle. */
|
|
30
|
+
@media (prefers-color-scheme: dark) {
|
|
31
|
+
:root:not([data-theme="light"]) {
|
|
32
|
+
--bg: #101720; --surface: #161f2a;
|
|
33
|
+
--ink: #e4ebf2; --ink-2: #a4b3c1; --ink-3: #7d8c9a;
|
|
34
|
+
--line: #2b3947; --line-soft: #223040;
|
|
35
|
+
--accent: #6fadd9; --accent-soft: #1d3346;
|
|
36
|
+
--bar: #4c88b4; --bar-hover: #6fadd9;
|
|
37
|
+
--good-ink: #57c48f; --good-bg: #16311f;
|
|
38
|
+
--warn-ink: #d9a94a; --warn-bg: #34290f;
|
|
39
|
+
--miss-ink: #e2857a; --miss-bg: #3a1d18;
|
|
40
|
+
--neutral-ink: #a4b3c1; --neutral-bg: #222d38;
|
|
41
|
+
--quote-rail: #33506a;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
:root[data-theme="dark"] {
|
|
45
|
+
--bg: #101720; --surface: #161f2a;
|
|
46
|
+
--ink: #e4ebf2; --ink-2: #a4b3c1; --ink-3: #7d8c9a;
|
|
47
|
+
--line: #2b3947; --line-soft: #223040;
|
|
48
|
+
--accent: #6fadd9; --accent-soft: #1d3346;
|
|
49
|
+
--bar: #4c88b4; --bar-hover: #6fadd9;
|
|
50
|
+
--good-ink: #57c48f; --good-bg: #16311f;
|
|
51
|
+
--warn-ink: #d9a94a; --warn-bg: #34290f;
|
|
52
|
+
--miss-ink: #e2857a; --miss-bg: #3a1d18;
|
|
53
|
+
--neutral-ink: #a4b3c1; --neutral-bg: #222d38;
|
|
54
|
+
--quote-rail: #33506a;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
body { background: var(--bg); color: var(--ink); font-family: ui-sans-serif, system-ui, "Segoe UI", "Helvetica Neue", Arial, sans-serif; font-size: 16px; line-height: 1.6; margin: 0; padding: 3rem 1.25rem 5rem; }
|
|
58
|
+
.doc { max-width: 46rem; margin: 0 auto; }
|
|
59
|
+
|
|
60
|
+
.eyebrow { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 0.75rem; }
|
|
61
|
+
h1 { font-family: ui-serif, Georgia, "Times New Roman", serif; font-weight: 700; font-size: 2.3rem; line-height: 1.15; margin: 0 0 0.5rem; text-wrap: balance; }
|
|
62
|
+
.dek { color: var(--ink-2); font-size: 1.05rem; max-width: 40rem; margin: 0 0 0.75rem; }
|
|
63
|
+
.meta { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.75rem; color: var(--ink-3); margin: 0 0 2.5rem; }
|
|
64
|
+
|
|
65
|
+
h2 { font-family: ui-serif, Georgia, "Times New Roman", serif; font-weight: 600; font-size: 1.45rem; line-height: 1.25; margin: 3rem 0 0.9rem; text-wrap: balance; }
|
|
66
|
+
h2 .sec { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-weight: 500; font-size: 0.78rem; color: var(--accent); display: block; letter-spacing: 0.12em; margin-bottom: 0.35rem; }
|
|
67
|
+
p { margin: 0 0 1rem; max-width: 42rem; }
|
|
68
|
+
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
|
|
69
|
+
strong { font-weight: 600; }
|
|
70
|
+
|
|
71
|
+
.tldr { background: var(--surface); border: 1px solid var(--line); border-left: 3px solid var(--accent); border-radius: 6px; padding: 1.15rem 1.35rem; margin: 0 0 1rem; }
|
|
72
|
+
.tldr p { margin: 0 0 0.7rem; }
|
|
73
|
+
.tldr p:last-child { margin: 0; }
|
|
74
|
+
|
|
75
|
+
figure { background: var(--surface); border: 1px solid var(--line); border-radius: 6px; margin: 1.5rem 0; padding: 1.25rem 1.35rem 1.1rem; }
|
|
76
|
+
figcaption { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 1rem; }
|
|
77
|
+
.fignote { font-size: 0.78rem; color: var(--ink-3); margin-top: 0.9rem; }
|
|
78
|
+
|
|
79
|
+
/* Frequency bar chart: single hue (one series = no legend), direct value labels, hover emphasis + title tooltips. */
|
|
80
|
+
.barchart { display: flex; flex-direction: column; gap: 7px; }
|
|
81
|
+
.barrow { display: grid; grid-template-columns: 13.5rem 1fr 2rem; gap: 0.7rem; align-items: center; font-size: 0.85rem; }
|
|
82
|
+
.barrow .lbl { color: var(--ink-2); text-align: right; line-height: 1.25; }
|
|
83
|
+
.track { background: var(--line-soft); border-radius: 3px; height: 16px; }
|
|
84
|
+
.fill { background: var(--bar); border-radius: 3px 4px 4px 3px; height: 100%; transition: background 120ms ease; }
|
|
85
|
+
.barrow:hover .fill { background: var(--bar-hover); }
|
|
86
|
+
.barrow .val { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-variant-numeric: tabular-nums; font-size: 0.8rem; color: var(--ink-2); }
|
|
87
|
+
.barrow:hover .lbl, .barrow:hover .val { color: var(--ink); }
|
|
88
|
+
|
|
89
|
+
/* Head-to-head stacked coverage bars, one row per proposal (+ a Merged row). */
|
|
90
|
+
.compare { display: flex; flex-direction: column; gap: 10px; }
|
|
91
|
+
.cmprow { display: grid; grid-template-columns: 8.5rem 1fr; gap: 0.8rem; align-items: center; }
|
|
92
|
+
.cmprow .who { font-size: 0.85rem; font-weight: 600; text-align: right; color: var(--ink-2); }
|
|
93
|
+
.scoreboard { display: flex; height: 26px; border-radius: 5px; overflow: hidden; gap: 2px; }
|
|
94
|
+
.scoreboard div { display: flex; align-items: center; justify-content: center; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.76rem; font-weight: 500; min-width: 1.4rem; }
|
|
95
|
+
.sc-good { background: var(--good-bg); color: var(--good-ink); }
|
|
96
|
+
.sc-warn { background: var(--warn-bg); color: var(--warn-ink); }
|
|
97
|
+
.sc-miss { background: var(--miss-bg); color: var(--miss-ink); }
|
|
98
|
+
.sc-legend { display: flex; gap: 1.4rem; margin-top: 0.8rem; font-size: 0.78rem; color: var(--ink-2); flex-wrap: wrap; }
|
|
99
|
+
.sc-legend span { display: inline-flex; align-items: center; gap: 0.4rem; }
|
|
100
|
+
.swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
|
|
101
|
+
|
|
102
|
+
/* Verdict + feasibility chips: text always, never color alone. */
|
|
103
|
+
.chip { display: inline-block; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.68rem; font-weight: 500; letter-spacing: 0.06em; padding: 0.15rem 0.5rem; border-radius: 999px; white-space: nowrap; }
|
|
104
|
+
.chip-good { background: var(--good-bg); color: var(--good-ink); } /* COVERED / API ✓ */
|
|
105
|
+
.chip-warn { background: var(--warn-bg); color: var(--warn-ink); } /* PARTIAL */
|
|
106
|
+
.chip-miss { background: var(--miss-bg); color: var(--miss-ink); } /* MISSED / NOT POSSIBLE */
|
|
107
|
+
.chip-api { background: var(--accent-soft); color: var(--accent); } /* vendor-supported rulings */
|
|
108
|
+
.chip-ours { background: var(--neutral-bg); color: var(--neutral-ink); } /* OUR BUILD / CONFIG */
|
|
109
|
+
|
|
110
|
+
.tablewrap { overflow-x: auto; margin: 1.5rem 0; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); }
|
|
111
|
+
table { border-collapse: collapse; width: 100%; font-size: 0.86rem; }
|
|
112
|
+
th { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); font-weight: 500; text-align: left; padding: 0.7rem 1rem; border-bottom: 1px solid var(--line); }
|
|
113
|
+
td { padding: 0.6rem 1rem; border-bottom: 1px solid var(--line-soft); vertical-align: top; color: var(--ink-2); }
|
|
114
|
+
td:first-child { color: var(--ink); font-weight: 600; }
|
|
115
|
+
tr:last-child td { border-bottom: none; }
|
|
116
|
+
td.nowrap { white-space: nowrap; }
|
|
117
|
+
|
|
118
|
+
blockquote { border-left: 3px solid var(--quote-rail); margin: 1.1rem 0; padding: 0.1rem 0 0.1rem 1.1rem; color: var(--ink-2); font-style: italic; max-width: 40rem; }
|
|
119
|
+
blockquote cite { display: block; font-style: normal; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.72rem; color: var(--ink-3); margin-top: 0.35rem; }
|
|
120
|
+
|
|
121
|
+
ol.twocents { padding-left: 1.3rem; max-width: 42rem; }
|
|
122
|
+
ol.twocents li { margin-bottom: 0.85rem; }
|
|
123
|
+
ol.twocents li::marker { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; color: var(--accent); font-size: 0.85rem; }
|
|
124
|
+
|
|
125
|
+
.method { border-top: 1px solid var(--line); margin-top: 3.5rem; padding-top: 1.25rem; font-size: 0.8rem; color: var(--ink-3); max-width: 42rem; }
|
|
126
|
+
</style>
|
|
127
|
+
|
|
128
|
+
<div class="doc">
|
|
129
|
+
<p class="eyebrow">Outside read · No stake in the outcome</p>
|
|
130
|
+
<h1>DOC NAME</h1>
|
|
131
|
+
<p class="dek">ONE-SENTENCE FRAME: who pulled what, and what this doc rules on.</p>
|
|
132
|
+
<p class="meta">~N messages · DATE → DATE · N channels/sources · input to DECISION/CARD</p>
|
|
133
|
+
|
|
134
|
+
<div class="tldr">
|
|
135
|
+
<p><strong>VERDICT SENTENCE.</strong> Two to three bold-led paragraphs; a reader who stops here can act.</p>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<h2><span class="sec">01</span>What the evidence says</h2>
|
|
139
|
+
<p>How findings were binned; what a count means.</p>
|
|
140
|
+
<figure>
|
|
141
|
+
<figcaption>FINDINGS BY INCIDENT COUNT, RANGE</figcaption>
|
|
142
|
+
<div class="barchart">
|
|
143
|
+
<!-- width = count / max * 100%. title attr = one-line version for hover. -->
|
|
144
|
+
<div class="barrow" title="ONE-LINER"><span class="lbl">CATEGORY</span><div class="track"><div class="fill" style="width:100%"></div></div><span class="val">15</span></div>
|
|
145
|
+
<div class="barrow" title="ONE-LINER"><span class="lbl">CATEGORY</span><div class="track"><div class="fill" style="width:60%"></div></div><span class="val">9</span></div>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="fignote">Dominant sources; hover note.</div>
|
|
148
|
+
</figure>
|
|
149
|
+
<blockquote>"VERBATIM QUOTE"<cite>WHO · #channel · DATE</cite></blockquote>
|
|
150
|
+
|
|
151
|
+
<h2><span class="sec">02</span>What already exists</h2>
|
|
152
|
+
<p>Incumbent system, prior art, negative results ("no payout code in the repo").</p>
|
|
153
|
+
|
|
154
|
+
<h2><span class="sec">03</span>PROPOSAL A, scored</h2>
|
|
155
|
+
<div class="tablewrap">
|
|
156
|
+
<table>
|
|
157
|
+
<thead><tr><th>Pain / need</th><th>Verdict</th><th>Why</th></tr></thead>
|
|
158
|
+
<tbody>
|
|
159
|
+
<tr><td>ITEM</td><td class="nowrap"><span class="chip chip-good">COVERED</span></td><td>ONE SENTENCE.</td></tr>
|
|
160
|
+
<tr><td>ITEM</td><td class="nowrap"><span class="chip chip-warn">PARTIAL</span></td><td>Symptom yes, root cause no.</td></tr>
|
|
161
|
+
<tr><td>ITEM</td><td class="nowrap"><span class="chip chip-miss">MISSED</span></td><td>ONE SENTENCE.</td></tr>
|
|
162
|
+
</tbody>
|
|
163
|
+
</table>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
<!-- Repeat 03 per proposal, then head-to-head: -->
|
|
167
|
+
<figure>
|
|
168
|
+
<figcaption>Head to head: N items each</figcaption>
|
|
169
|
+
<div class="compare">
|
|
170
|
+
<div class="cmprow"><span class="who">Proposal A</span>
|
|
171
|
+
<div class="scoreboard"><div class="sc-good" style="flex:3">3</div><div class="sc-warn" style="flex:5">5</div><div class="sc-miss" style="flex:3">3</div></div>
|
|
172
|
+
</div>
|
|
173
|
+
<div class="cmprow"><span class="who">Merged</span>
|
|
174
|
+
<div class="scoreboard"><div class="sc-good" style="flex:10">10</div><div class="sc-warn" style="flex:1">1</div></div>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="sc-legend">
|
|
178
|
+
<span><span class="swatch" style="background:var(--good-bg);border:1px solid var(--good-ink)"></span>covered</span>
|
|
179
|
+
<span><span class="swatch" style="background:var(--warn-bg);border:1px solid var(--warn-ink)"></span>symptom yes, root cause no</span>
|
|
180
|
+
<span><span class="swatch" style="background:var(--miss-bg);border:1px solid var(--miss-ink)"></span>not in the plan</span>
|
|
181
|
+
</div>
|
|
182
|
+
</figure>
|
|
183
|
+
|
|
184
|
+
<h2><span class="sec">04</span>The merged plan, with rulings</h2>
|
|
185
|
+
<div class="tablewrap">
|
|
186
|
+
<table>
|
|
187
|
+
<thead><tr><th>Blueprint item</th><th>Feasibility</th><th>Detail</th></tr></thead>
|
|
188
|
+
<tbody>
|
|
189
|
+
<tr><td>ITEM</td><td class="nowrap"><span class="chip chip-api">API ✓</span></td><td>Ruling + <a href="ENDPOINT-DOC-URL">endpoint link</a>.</td></tr>
|
|
190
|
+
<tr><td>ITEM</td><td class="nowrap"><span class="chip chip-ours">OUR BUILD</span></td><td>Ruling.</td></tr>
|
|
191
|
+
<tr><td>ITEM</td><td class="nowrap"><span class="chip chip-miss">NOT POSSIBLE</span></td><td>Why, and whether the impossibility is desirable.</td></tr>
|
|
192
|
+
</tbody>
|
|
193
|
+
</table>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<h2><span class="sec">05</span>The two cents</h2>
|
|
197
|
+
<ol class="twocents">
|
|
198
|
+
<li><strong>RECOMMENDATION.</strong> The argument for it.</li>
|
|
199
|
+
</ol>
|
|
200
|
+
|
|
201
|
+
<div class="method">
|
|
202
|
+
<p><strong>Method.</strong> Queries run, counts, date range, what was reviewed in full, what was verified against primary sources, and what was NOT done.</p>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: conveyor-local-loop
|
|
3
|
-
description: Run this machine as a serial local claudespace — pick the session owner's highest-priority Open Conveyor card, claim it, execute its plan to the PR finish line, repeat. Handles single cards AND whole packs (an Open pack parent is driven end-to-end per conveyor-
|
|
3
|
+
description: Run this machine as a serial local claudespace — pick the session owner's highest-priority Open Conveyor card, claim it, execute its plan to the PR finish line, repeat. Handles single cards AND whole packs (an Open pack parent is driven end-to-end per conveyor-build's pack path, then the loop moves on once the pack's final PR is open). One invocation = one iteration; run continuously with "/loop /conveyor-local-loop" (no interval) and it self-paces (~1-2 min between cards while the queue has work; when the queue is empty it blocks on live board events via conveyor-wait and wakes seconds after a card becomes claimable, with a ~25 min fallback poll). Use when the user says "/conveyor-local-loop", "start the local loop", "work my open cards locally", or wants planned cards executed with full local CPU/RAM instead of spawning claudespaces. For exactly one card, or one pack and nothing else, use conveyor-build.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Conveyor Local Loop
|
|
@@ -29,7 +29,7 @@ adds only selection, claiming, cadence, and local-machine hygiene.
|
|
|
29
29
|
- **Pack cards: claim the whole pack; the parent card stays parked.** An Open
|
|
30
30
|
feature-branch pack parent that passes the claiming filters is claimable as
|
|
31
31
|
a PACK: enter pack mode (below) and drive every child to the final parent
|
|
32
|
-
PR per [conveyor-
|
|
32
|
+
PR per [conveyor-build's pack path](../conveyor-build/references/pack-path.md). Throughout,
|
|
33
33
|
the parent card itself stays PARKED — never Build/`start_task` it, never
|
|
34
34
|
set it InProgress; the finale `create_pull_request` is what moves it to
|
|
35
35
|
ReviewPR. A parent already InProgress/ReviewPR has (or had) an active
|
|
@@ -38,7 +38,7 @@ adds only selection, claiming, cadence, and local-machine hygiene.
|
|
|
38
38
|
"recovers" it onto a cloud pod (observed 2026-07-28 — duplicate
|
|
39
39
|
implementation). A NON-feature-branch pack — children PR straight into dev,
|
|
40
40
|
so there is no pack branch to coordinate — is never claimed as a pack:
|
|
41
|
-
|
|
41
|
+
conveyor-build's pack path explicitly does not apply to it. Claim those children
|
|
42
42
|
individually, one per iteration, and only while the parent is parked.
|
|
43
43
|
- **Run in the main workspace checkout — never a git worktree.** The fully
|
|
44
44
|
provisioned main workspace (installed `node_modules`, `.env`/direnv auth
|
|
@@ -101,34 +101,23 @@ Each invocation does the FIRST of these that produces work, then paces:
|
|
|
101
101
|
|
|
102
102
|
## Execute and finish
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
attach via `mcp__conveyor__upload_attachment` before opening the PR.
|
|
122
|
-
5. Refresh against the card's base (`git fetch origin <base> && git merge
|
|
123
|
-
origin/<base> --no-edit && git push`), then
|
|
124
|
-
`mcp__conveyor__create_pull_request` with `head:` your branch and `base:`
|
|
125
|
-
the card's base branch. Pack child: re-check the parent's status first —
|
|
126
|
-
if it went InProgress/ReviewPR, park instead (post `[local-loop] parked:
|
|
127
|
-
pack coordinator active — yielding`, leave the branch pushed) and let the
|
|
128
|
-
coordinator take over. The card moves to ReviewPR. Post a chat summary:
|
|
129
|
-
what shipped, how verified, what to look at.
|
|
130
|
-
6. Confirm CI actually started (read-only `gh pr checks`); do NOT wait on it —
|
|
131
|
-
later iterations babysit.
|
|
104
|
+
**Execution is [conveyor-build](../conveyor-build/SKILL.md)** — resolving the
|
|
105
|
+
card, branching from its base, working the plan, gating, and opening the PR
|
|
106
|
+
with an explicit `base:`. That skill is the source of truth; do not re-derive
|
|
107
|
+
its procedure here. It routes a childless card to its task path and a
|
|
108
|
+
feature-branch pack to its pack path automatically.
|
|
109
|
+
|
|
110
|
+
This section adds only what the LOOP changes:
|
|
111
|
+
|
|
112
|
+
- **Chat markers carry the loop's prefix**, `[local-loop]` rather than
|
|
113
|
+
`[build]`, because the Recover tier greps for them to find its own work.
|
|
114
|
+
- **A pack child yields to a live coordinator.** Before opening a child's PR,
|
|
115
|
+
re-check the parent's status; if it went InProgress or ReviewPR, post
|
|
116
|
+
`[local-loop] parked: pack coordinator active — yielding`, leave the branch
|
|
117
|
+
pushed, and let the coordinator take over.
|
|
118
|
+
- **Do not wait on CI.** Confirm it started (read-only `gh pr checks`) and end
|
|
119
|
+
the iteration — the Babysit tier owns it from there. This is the loop's one
|
|
120
|
+
real departure from a standalone build, which stays with its PR.
|
|
132
121
|
|
|
133
122
|
**Parked protocol** — after 2 genuinely different failed approaches, or on a
|
|
134
123
|
decision only the user can make: post `[local-loop] parked: <reason + the
|
|
@@ -139,12 +128,13 @@ signal.
|
|
|
139
128
|
## Pack mode
|
|
140
129
|
|
|
141
130
|
Claiming an Open pack parent means driving the ENTIRE pack, exactly per
|
|
142
|
-
[conveyor-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
131
|
+
[conveyor-build's pack path](../conveyor-build/references/pack-path.md) —
|
|
132
|
+
setup (pack branch on origin, the `githubBranch` write-through, child breakdown
|
|
133
|
+
if the parent has none yet), children serially in dependency order,
|
|
134
|
+
reviewer-of-record review + merge of each child PR into the pack branch,
|
|
135
|
+
dev→pack sync after every merge, cross-reference, then the finale parent PR
|
|
136
|
+
into dev. That reference is the source of truth for the procedure; this section
|
|
137
|
+
only defines how it embeds in the loop:
|
|
148
138
|
|
|
149
139
|
- The pack occupies the loop's single WIP slot from claim until the finale PR
|
|
150
140
|
opens. Do not interleave unrelated cards mid-pack — that thrashes branch
|
|
@@ -155,8 +145,8 @@ section only defines how it embeds in the loop:
|
|
|
155
145
|
- Once the finale PR is open (parent in ReviewPR), the pack leaves the WIP
|
|
156
146
|
slot: its PR joins the Babysit tier like any other loop-opened PR, and the
|
|
157
147
|
loop resumes claiming other cards. This is the one difference from
|
|
158
|
-
standalone
|
|
159
|
-
- Parked children follow
|
|
148
|
+
a standalone conveyor-build pack run, which stops when the pack is done.
|
|
149
|
+
- Parked children follow the pack path's parked protocol. If every
|
|
160
150
|
remaining child is blocked on the user, the pack yields the WIP slot: post
|
|
161
151
|
`[local-loop] parked: <what it is waiting on>` to the PARENT chat — that
|
|
162
152
|
marker is what makes the Recover tier skip the pack — and the loop claims
|
|
@@ -248,8 +238,11 @@ depth each iteration so the user can offload manually.
|
|
|
248
238
|
|
|
249
239
|
## What this is not
|
|
250
240
|
|
|
251
|
-
- Not a reviewer
|
|
252
|
-
`request_changes` on
|
|
241
|
+
- Not a reviewer of anything headed for `dev`: never `approve_task`,
|
|
242
|
+
`request_changes`, or `approve_and_merge_pr` on a PR into `dev` — including
|
|
243
|
+
a pack's final parent PR. **The one exception is a pack's CHILD PRs into the
|
|
244
|
+
pack branch**, where you are the reviewer of record because the automated
|
|
245
|
+
reviewer skips that target; the pack path spells out that duty.
|
|
253
246
|
- Not a pod: no sandbox, no WIP snapshots, and the dev DB + dev-server ports
|
|
254
247
|
are shared with the user's interactive sessions — no destructive
|
|
255
248
|
experiments, never reset the dev DB, reuse a running dev stack rather than
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: conveyor-meeting-review
|
|
3
|
+
description: Turn a Conveyor meeting into confirmed cards, packs, and glossary updates — read the meeting and its transcript, cross-reference what already exists, draft proposals at the plan-quality bar, and create only what a human confirms item by item. Use when the user says "/conveyor-meeting-review <meeting>", "turn that meeting into cards", "what should we do about yesterday's call", or asks for the follow-ups from a meeting. Never creates anything unasked.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Conveyor Meeting Review
|
|
7
|
+
|
|
8
|
+
A meeting becomes work only when a person says which parts should. This skill does the reading, the cross-referencing, and the drafting — and then **stops and asks**.
|
|
9
|
+
|
|
10
|
+
## The one rule
|
|
11
|
+
|
|
12
|
+
**Never create, edit, or tag anything before a human confirms that specific item.** Not "shall I proceed?" and then everything — item by item, so "create 1 and 3, skip 2" is a normal answer.
|
|
13
|
+
|
|
14
|
+
This is not caution for its own sake. A meeting transcript is full of things that *sound* like decisions: someone thinking out loud, an idea that was argued down two minutes later, a "we should probably…" that nobody agreed to. An agent that creates cards from those is manufacturing work the team never chose, on a board they have to clean up. The summary's `## Proposed Next Steps` is a **starting point, not a mandate** — it was written by a model reading the same ambiguous transcript.
|
|
15
|
+
|
|
16
|
+
## 1 — Read
|
|
17
|
+
|
|
18
|
+
1. `mcp__conveyor__get_connection_context` — where you are. Same call in a pod and a local MCP session.
|
|
19
|
+
2. `mcp__conveyor__get_meeting` — the overview, the decisions, the proposed next steps, and the participants. **This usually answers the question.** It costs a fraction of the transcript.
|
|
20
|
+
3. `mcp__conveyor__read_meeting_transcript` — only when you need exact wording: a quote, a caveat, the reasoning behind a decision the summary merely states, or a check on whether something was actually agreed. Page with `offset`/`nextOffset` rather than pulling the whole thing.
|
|
21
|
+
|
|
22
|
+
If `status` is `processing` the summary is still being written — read the transcript, or say so and offer to come back. If `status` is `failed`, `summaryError` says why; the transcript is still complete and readable.
|
|
23
|
+
|
|
24
|
+
## 2 — Cross-reference before drafting anything
|
|
25
|
+
|
|
26
|
+
Skipping this is how a meeting review produces four cards that duplicate work already in flight.
|
|
27
|
+
|
|
28
|
+
- `mcp__conveyor__list_tags` — the project's vocabulary. Use its words in your proposals; a card that names the same thing differently is a card nobody finds.
|
|
29
|
+
- `mcp__conveyor__search_tasks` — **two or three keyword variants per proposed topic**, across `task`, `incident` and `suggestion`. One search misses the card that used the other word for it.
|
|
30
|
+
- `mcp__conveyor__read_task_chat` on anything that looks close. The overlap is usually in the discussion, not the title.
|
|
31
|
+
|
|
32
|
+
Then say what you found, including the negatives: "this one already exists as `fix-the-thing`", "nothing on the board covers this", "there is a suggestion arguing the opposite".
|
|
33
|
+
|
|
34
|
+
## 3 — Draft at the plan-quality bar
|
|
35
|
+
|
|
36
|
+
Each proposal a context-free reader could execute: what changes, where (file paths where you know them), and how it is verified. The `/conveyor-plan` skill's `references/plan-format.md` is the bar. A one-line card that says "improve onboarding" is not a proposal, it is a note.
|
|
37
|
+
|
|
38
|
+
Classify honestly:
|
|
39
|
+
|
|
40
|
+
- **A card** — one coherent piece of work.
|
|
41
|
+
- **A pack** — a parent plus children, when the work has real internal ordering. Do not inflate a card into a pack for ceremony.
|
|
42
|
+
- **An edit to an existing card** — usually better than a new one when something is already in flight. Say which card and what changes.
|
|
43
|
+
- **A tag update** — the glossary learned a word.
|
|
44
|
+
- **A suggestion** — the meeting raised something worth recording that nobody has decided to do. This is the honest home for "we should look into X someday", and it keeps the board clean.
|
|
45
|
+
- **Nothing** — some meetings produce no work. Say so rather than finding something.
|
|
46
|
+
|
|
47
|
+
## 4 — Present and wait
|
|
48
|
+
|
|
49
|
+
Number the proposals. For each: the type, the title, one sentence of what it is, and — critically — **what in the meeting supports it**, with a speaker and roughly when. A proposal whose evidence you cannot name is one you inferred, and it should be labelled as such or dropped.
|
|
50
|
+
|
|
51
|
+
Flag separately:
|
|
52
|
+
|
|
53
|
+
- **Decisions that need a human**, which a card cannot settle.
|
|
54
|
+
- **Contradictions** — where the meeting disagreed with itself, or with a card already on the board.
|
|
55
|
+
- **Things you deliberately did not propose**, and why. That is often the most useful part.
|
|
56
|
+
|
|
57
|
+
Then wait. If the reply is partial ("1 and 3"), create exactly those.
|
|
58
|
+
|
|
59
|
+
## 5 — Create, and stamp the provenance
|
|
60
|
+
|
|
61
|
+
Only the confirmed items, through the normal card tools — `create_task`, `create_subtask`, `add_dependency`, `update_task`, `manage_tags`, `create_suggestion`. There is no meeting-specific write path, on purpose: a card born from a meeting should be indistinguishable from any other card, and reviewable the same way.
|
|
62
|
+
|
|
63
|
+
**Stamp every created card with the meeting link** from `get_meeting`'s `url` field, in the description or the plan. Six weeks later "why does this card exist" is a real question, and the answer should be one click away.
|
|
64
|
+
|
|
65
|
+
Report back with what was created and what was skipped.
|
|
66
|
+
|
|
67
|
+
## Environment notes
|
|
68
|
+
|
|
69
|
+
- All Conveyor tools are **fully qualified** (`mcp__conveyor__get_meeting`); bare names fail.
|
|
70
|
+
- The meeting tools are **deferred** — reach them via ToolSearch rather than expecting them preloaded.
|
|
71
|
+
- They appear only for a project that HAS meetings. If they are absent, the project has none; say so instead of hunting.
|
|
72
|
+
- A pod and a local MCP session run this identically. The only difference is where you report: in a pod, card chat.
|