---
name: glab-epic-create
description: >
  Generate or update a GitLab epic description from its child issues, or create a new epic
  from scratch by finding issues matching a theme.
  Use when the user says /glab-epic-create, 'décris cette epic', 'résume l epic',
  'rédige la description de l epic', 'crée une epic sur', 'nouvelle epic',
  'epic description from issues', 'mets à jour la description de l epic',
  or wants to auto-fill an epic's description from its linked issues.
argument-hint: "<epic IID or URL> | <theme description> [--dry-run]"
allowed-tools:
  - Bash
  - AskUserQuestion
---

Two modes: **update** an existing epic's description from its child issues, or **create** a new epic from scratch by finding issues matching a theme.

## Required tools

- `glab`

Run `pysae-ai-tools tools require <tools>` before starting; if it exits non-zero, abort and report the install command from stderr to the user.

## Mode detection

```bash
CTX=$(pysae-ai-tools internal detect-context)
IS_CI=$(echo "$CTX" | jq -r '.is_ci')
```

In CI mode: never use `AskUserQuestion`, apply directly and exit.

## Scenario detection

Parse `$ARGUMENTS`:
- If the argument is a **number** (e.g. `42`) or a **GitLab epic URL** → **Scenario A** (update existing epic)
- If the argument is **free text** describing a theme (e.g. « amélioration de l'export GTFS », « refonte notifications ») → **Scenario B** (create new epic)

---

## Scenario A — Update existing epic

### Step A1 — Resolve the epic

```bash
EPIC=$(glab api "groups/pysae/epics/${EPIC_IID}")
EPIC_TITLE=$(echo "$EPIC" | jq -r '.title')
CURRENT_DESC=$(echo "$EPIC" | jq -r '.description // empty')
```

If the epic already has a non-empty description, show it to the user and ask:
> L'epic #${EPIC_IID} a déjà une description. Tu veux la **remplacer** ou **compléter** ?

### Step A2 — Fetch the epic template

Retrieve the latest epic template **before** analysing child issues, so all sections are known upfront:
```bash
EPIC_TEMPLATE=$(glab api "projects/pysae%2Fissue-templates/repository/files/.gitlab%2Fissue_templates%2Fepic.md/raw?ref=main" 2>/dev/null)
```
Read the template carefully — it defines the mandatory sections (headings, order, emoji, separators).

### Step A3 — Fetch child issues

```bash
pysae-ai-tools glab epic-from-issues --epic ${EPIC_IID}
```

The script fetches all child issues (open + closed) and outputs a JSON summary with per-issue details and aggregated stats.

### Step A4 — Draft and apply

Continue to [Draft the description](#draft-the-description) below.

---

## Scenario B — Create epic from theme

### Step B1 — Search issues matching the theme

Use the theme keywords to search for open issues across the group:

```bash
# Search by keywords extracted from the theme
pysae-ai-tools glab epic-attach-issues --scoring-mode claude --search "<keyword1>" --search "<keyword2>"
```

If `epic-attach-issues` is too broad, fall back to a direct API search:
```bash
glab api "groups/pysae/issues?state=opened&search=<keyword>&in=title,description&per_page=100"
```

From the results, select the issues that genuinely match the theme. Include issues from any project — epics are cross-project.

### Step B2 — Present candidate issues for validation

Present the found issues to the user:

> **Création d'epic — thème : « ${THEME} »**
>
> ${N} tickets trouvés correspondant à ce thème :
>
> | # | Projet | Titre | Labels |
> |---|--------|-------|--------|
> | #IID | project | title | labels |
>
> **Actions :**
> - **Valider tout** — créer l'epic avec ces ${N} tickets
> - **Sélectionner** — spécifier les numéros à inclure (ex : « 1, 3, 5 »)
> - **Ajouter** — rechercher d'autres tickets avec des mots-clés supplémentaires
> - **Annuler**

Iterate until the user confirms a set of issues.

### Step B3 — Choose the epic title

Propose an English title for the epic, inferred from the selected issues and the user's theme description:

> **Titre proposé :** `Improve GTFS export pipeline`
>
> **Actions :**
> - **Valider** — utiliser ce titre
> - **Modifier** — proposer un autre titre

### Step B4 — Create the epic

```bash
RESPONSE=$(glab api -X POST "groups/pysae/epics" \
  -H "Content-Type: application/json" \
  --input - <<< "$(jq -n --arg title "$EPIC_TITLE" '{title: $title}')")
EPIC_IID=$(echo "$RESPONSE" | jq -r '.iid')
```

### Step B5 — Attach issues to the epic

Attach all selected issues:

```bash
pysae-ai-tools glab epic-attach --epic ${EPIC_IID} \
  --issue project1#iid1 --issue project2#iid2 ...
```

The command handles ID resolution and reports errors for incompatible work item types.

Report progress:
> Rattaché ${X}/${Y} tickets à l'epic #${EPIC_IID}.

### Step B6 — Draft and apply

Fetch the freshly created epic's child issues:
```bash
pysae-ai-tools glab epic-from-issues --epic ${EPIC_IID}
```

Continue to [Draft the description](#draft-the-description) below.

---

## Draft the description

From the script output, analyse all child issues and draft a structured epic description in **French**, following [../references/french-writing-rules.md](../references/french-writing-rules.md):

### Title update

If the current epic title does not accurately reflect the child issues' theme, propose an updated title. Epic titles follow the format `[YYYY-SN] Titre de l'epic` where `YYYY` is the year and `SN` the semester (S1 = Jan-Jun, S2 = Jul-Dec). Keep the existing `[YYYY-SN]` prefix, only update the descriptive part. The title is written in **French**.

When the epic was **created by automation** (title contains `WIP` or `[AI]`), always propose a proper title. Place `[AI]` between the semester prefix and the title (e.g. `[2026-S1] [AI] Migration nginx → Kong`). The user will remove the tag manually after validation.

### Description structure

The description **must** follow the fetched template exactly: same sections, same order, same heading format. Replace the placeholder text (in `> _italics_`) with actual content inferred from the child issues. Additional sections may be appended after the last template section, but no template section may be removed or reordered.

**Guidelines:**
- Infer the epic's purpose from the child issue titles and descriptions — do not just list the issues
- Identify common themes, affected components, and the overall goal
- Use concise, professional language
- If the issues span multiple projects, mention the cross-project nature
- **Never reference individual tickets** (no `#IID`, `repo#IID`, or issue links) — the child issues are already visible in the epic sidebar, the description must stay high-level

## Confirm with the user

Present the draft description using `AskUserQuestion`:

> **Epic #${EPIC_IID}**
>
> **Titre :** `${NEW_TITLE}` *(inchangé si le titre actuel convient)*
>
> **Description :**
> <rendered description>
>
> **Actions :**
> - **Appliquer** — mettre à jour le titre et la description de l'epic
> - **Modifier** — demander des ajustements
> - **Annuler**

If the user asks for modifications, adjust and re-present.

If `--dry-run` is in `$ARGUMENTS`, display the draft without applying.

## Apply the description

Update the epic title and description via the API:

```bash
glab api -X PUT "groups/pysae/epics/${EPIC_IID}" \
  -H "Content-Type: application/json" \
  --input - <<< "$(jq -n --arg title "$NEW_TITLE" --arg desc "$DESCRIPTION" '{title: $title, description: $desc}')"
```

If the title is unchanged, omit the `title` field. Confirm:
> Epic #${EPIC_IID} mise à jour.

## Rules

- **Never delete or close** issues or epics — only create epics, attach issues, and update descriptions
- **French** for epic descriptions (following [../references/french-writing-rules.md](../references/french-writing-rules.md)) — epic titles remain in English
- **Infer the purpose** — do not just list issues, synthesize the common theme
- **Respect `--dry-run`** — never mutate when dry-run is set
- **Preserve existing content** — if the user chooses to append (Scenario A), place the generated content after the existing description separated by a `---`
- **Always use `pysae-ai-tools glab epic-attach`** for attaching issues to epics. The `/parent_epic` quick action only works in issue descriptions at creation time, not via the notes API

$ARGUMENTS
