# Design: close the PM loop for gemma-data-team

**Date**: 2026-06-22
**Plugin**: gemma-data-team
**Author**: Jan Oboth

---

## Summary

The `gemma-data-team` plugin runs a Claude Code *agent team*: a **lead** orchestrator spawns role teammates (DE/AE/DA/DS/QA) plus an intake agent (`ticket-fetcher`) and a self-improvement agent (`learning-synthesizer`). Today the loop only **pulls** work *from* a PM tool, and the fetcher enqueues whatever it finds in no particular order.

This work closes the project-management loop:

1. **Notes → tickets** — distill action items from meeting notes (Fireflies / Gemini / personal notes) and post them to the PM tool, where the existing `ticket-fetcher` picks them up. The mirror image of the fetcher.
2. **Prioritization** — the fetcher preserves the PM tool's native priority + due date so the lead can sequence work.
3. **Loop-closing extras** — write PR status back to tickets, generate status reports, and groom/estimate the backlog.

Two existing invariants govern every piece:

- **Credential boundary** — peer agents cannot do credentialed I/O (`op read`, authenticated HTTP); only the **lead** (main session) holds the user's authorization. So *posting to ClickUp is always done by the lead*. Reading local note files needs no credentials, so a peer agent can do that part.
- **Hard QA gate** — unchanged; this work does not touch it.

---

## Scope

### In scope (Phase 1 — core intake)
- New skill `plugins/gemma-data-team/skills/capture-tickets-from-notes/`
  - `SKILL.md`
  - `references/notes-config.md`
- New agent `plugins/gemma-data-team/agents/note-scout.md`
- Edit `plugins/gemma-data-team/agents/ticket-fetcher.md` — capture native priority + due date
- Edit `plugins/gemma-data-team/skills/launch-data-team/SKILL.md` — priority-aware sequencing + note-scout in roster

### In scope (Phase 2 — loop-closing extras)
- New skill `plugins/gemma-data-team/skills/update-ticket-status/SKILL.md`
- New skill `plugins/gemma-data-team/skills/team-status-report/SKILL.md`
- New skill `plugins/gemma-data-team/skills/groom-backlog/SKILL.md`

### Cross-cutting
- Edit `plugins/gemma-data-team/README.md`

### Out of scope
- No new plugin (everything lives in `gemma-data-team`; no new release-please registration).
- No separate prioritization/triage agent — prioritization is an attribute the existing fetcher carries.
- No change to the hard QA gate, the connection-mode policy, or the existing doer roles.
- The API notes source (Fireflies/Drive) is **documented and lead-fed**, not fully automated in Phase 1.

---

## Locked decisions (from brainstorming)

| Decision | Choice | Rationale |
|---|---|---|
| Notes source | Both/configurable | Local notes dir (primary, no auth) + optional lead-fed API source |
| Data protection | API + aggressive scrub | Runs on Anthropic API; distill step strips client names/figures/PII. **Not** Bedrock-gated, but the reference doc recommends Bedrock for sensitive client notes |
| Prioritization | Extend `ticket-fetcher` | PM tools already have priority + due date; preserve them, lead sequences |
| Form factor | Skill + team agent | `capture-tickets-from-notes` skill (lead/solo, has creds) + `note-scout` peer agent (reads/distills, no creds) |
| Posting gate | Approval-first | Show scrubbed drafts; post only what's approved (mirrors `learning-synthesizer`) |
| Build order | One spec, phased | Phase 1 ships independently of Phase 2 |

---

## Phase 1a — Notes → tickets

### Skill `capture-tickets-from-notes`

Frontmatter: `name: capture-tickets-from-notes`, `disable-model-invocation: true` (creates tickets — side effect), `argument-hint: "[project path or notes scope]"`.

Flow (run by lead/solo — holds credentials):

1. **Resolve notes config** — read a `## Meeting notes` section in the project `CLAUDE.md`, falling back to `.gemma/notes-config.yml`. (Same resolution idea as `gemma-dbt/validate-repo`'s target-structure lookup.) Config: `notes_dir`, optional `api_source` (`fireflies`/`gdrive` + a 1Password item *reference*, never an inline secret), `clickup` target list/space.
2. **Detect new notes** since last run via state marker `.gemma/notes-state.json` — per note: path + content hash + last-processed timestamp (API sources: transcript IDs). New/changed = absent or hash mismatch.
3. **Distill + scrub** action items → proposed tickets. Each: imperative title, generic+actionable description, discipline-tag guess (`de/ae/da/ds/qa`), source attribution (note filename + date — **not** raw content), priority/due if the note states them. Scrub strips client names, revenue, PII.
4. **Dedup** against existing PM-tool tickets and the project `MEMORY.md` (reuse the fetcher's dedup discipline).
5. **Approval gate** — present drafts as a review table; user approves / edits / drops.
6. **Post approved** to the PM tool (tool-agnostic via MCP or API; lead holds creds). Record posted ticket IDs into `.gemma/notes-state.json` so they aren't re-proposed.

### Agent `note-scout`

Frontmatter: `name: note-scout`, `tools: Read, Grep, Glob, Bash, TaskCreate, TaskGet, TaskList`, `model: inherit`.

Peer intake agent, mirror of `ticket-fetcher`. Reads local notes (no creds), distills + scrubs, proposes tickets, dedups against `MEMORY.md`, and hands drafts to the **lead** to post — explicitly states it does not post or read secrets itself (same credential-boundary wording as `ticket-fetcher`).

### Reference `notes-config.md`

Config schema, scrubbing rules, and the data-protection caveat (this path is API-allowed but not gated; prefer Bedrock for sensitive client notes).

---

## Phase 1b — Prioritization (extend the fetcher)

`ticket-fetcher.md`:
- "What you produce" gains: capture native **priority** (urgent/high/normal/low) and **due date** as task tags (`prio:high`, `due:2026-07-01`). Absent at source → `prio:unset`, surfaced — never invent a priority.
- New "Prioritization & ordering" section: fetcher records priority + due + the dependency edges it already creates; the **lead sequences** by (1) dependency order, (2) priority, (3) due date.

`launch-data-team/SKILL.md`:
- Step 5 references priority-aware sequencing.
- `note-scout` added to the roster / fetch-backlog step as an optional intake teammate.

---

## Phase 2 — Loop-closing extras

All three: lead-run, `disable-model-invocation: true`, tool-agnostic, under `skills/`.

| Skill | Does | Notes |
|---|---|---|
| `update-ticket-status` | Reads the originating ticket ID from a PR (process-ticket already mandates the ticket link), maps PR state → PM-tool status, comments the PR URL on the ticket | Document an optional opt-in hook to fire on PR creation (mirrors learning-synthesizer's optional Stop hook) |
| `team-status-report` | Reads task list (`TaskList`/`TaskGet`) + recent PRs (`gh`) + QA verdicts; emits a Markdown digest (shipped / in-flight / blocked / QA-pending); optionally posts to ClickUp or Slack | Work items only — no client data |
| `groom-backlog` | t-shirt effort sizing (S/M/L) per ticket from discipline + scope heuristics; flags under-specified (missing acceptance criteria) and stale tickets | Advisory output; modifies the PM tool only on approval |

---

## Constraints (from repo conventions)

- SKILL.md must be under 500 lines; push detail to `references/`.
- `name` in frontmatter must match the folder/file name (CI-enforced).
- `disable-model-invocation: true` on every side-effecting skill (CI/plugin convention).
- Scripts referenced via `${CLAUDE_SKILL_DIR}/...`; any Python uses the `uv` standalone pattern.
- Kebab-case folders; `<placeholder_name>` snake_case.
- Commits: `feat(gemma-data-team): …` (same plugin → no new release-please entry).
- Credential boundary respected throughout: peers read/distill, lead posts.

---

## Verification

- **Structural** — pass `validate-plugins.yml` locally (frontmatter present, `name` matches folder, side-effecting skills carry `disable-model-invocation`, `${CLAUDE_SKILL_DIR}` for script paths).
- **Skill discovery** — new skills load with clear descriptions.
- **Notes-intake dry run** — synthetic, non-client fixture notes dir: new-note detection (state marker), scrubbing, approval flow, dedup against a stub `MEMORY.md`, post step gated behind approval. No real client notes.
- **Fetcher regression** — priority-capture edits keep the existing intake/classification flow internally consistent.
- **Phase independence** — Phase 1 ships and works with no Phase 2 skill present.
