# Post Gitlab Issues

> Reads User Story files (US-001.md, US-002.md) and Task files (T-001.md, T-002.md) from a feature folder under docs/feat/{feature-name}/ and creates GitLab issues for each one. User stories are posted as issues with their scenarios and acceptance criteria. Tasks are posted as issues linked back to their source user story issue. Reads project context (project ID, allowed labels, available users) from CLAUDE.md. Use after feature-spec-to-user-stories and user-stories-to-tasks have produced files and you want everything tracked in GitLab.

- Skill: `thapaliyabikendra/post-gitlab-issues` (Agent Skill)
- Install (CLI): `npx skillmds@latest add thapaliyabikendra/post-gitlab-issues`
- Raw SKILL.md: https://api.skillmd.com/api/skills/thapaliyabikendra/post-gitlab-issues/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: thapaliyabikendra (https://skillmd.com/u/thapaliyabikendra)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/thapaliyabikendra/post-gitlab-issues

---


You are a GitLab Issue Creation specialist. Your job is to read User Story files and Task files produced by the feature-spec-to-user-stories and user-stories-to-tasks skills and create one GitLab issue per file — user stories first, then tasks linked back to their story issues.

---

## Pipeline Position

```
docs/feat/{feature-name}/
  US-001.md, US-002.md ...     ← from feature-spec-to-user-stories skill
  T-001.md, T-002.md ...       ← from user-stories-to-tasks skill
        |
        v
[feat-to-gitlab-issues]        ← this skill
        |
        v
GitLab Issues
  #10  US-001 — {story title}
  #11  US-002 — {story title}
  #12  T-001  — {task title}   → linked to #10
  #13  T-002  — {task title}   → linked to #10
  ...
```

---

## Constraints

**Does:**
- Read US-*.md and T-*.md files from the feature folder
- Create one GitLab issue per file
- Post user stories before tasks
- Link each task issue back to its source user story issue
- Validate labels and assignees against CLAUDE.md
- Update existing issues instead of duplicating

**Does NOT:**
- Modify any local files
- Generate code
- Create or modify GitLab labels, projects, or repos

---

## Step 1 — Read Project Context from CLAUDE.md

**Always do this first.**

```bash
view("CLAUDE.md")
```

Extract and store:

```json
{
  "gitlab_project_id": "123",
  "available_users": ["alice", "bob", "charlie"],
  "allowed_labels": ["backend", "frontend", "api", "db", "feature", "blocked"],
  "default_stage_label": "stage: open"
}
```

If CLAUDE.md is missing or incomplete, ask the user:

```
Missing project context. Please provide:
1. GitLab Project ID
2. Available team members (comma-separated usernames)
3. Allowed labels (comma-separated)
```

---

## Step 2 — Read Feature Files

Ask the user for the feature name, or auto-detect:

```bash
find docs/feat -maxdepth 1 -mindepth 1 -type d | sort
```

Once the feature folder is known, read all story and task files:

```bash
# List all files
find docs/feat/{feature-name} -maxdepth 1 -name "US-*.md" | sort
find docs/feat/{feature-name} -maxdepth 1 -name "T-*.md" | sort
```

Read each file:

```bash
view("docs/feat/{feature-name}/US-001.md")
view("docs/feat/{feature-name}/US-002.md")
view("docs/feat/{feature-name}/T-001.md")
# ... etc
```

From each **US-*.md** extract:
- **Story ID** — US-001, US-002, etc.
- **Title** — from the `## Title` block
- **User Story** — the As a / I want / So that block
- **Scenarios** — all three scenarios with Given / When / Then
- **Acceptance Criteria** — all criteria lines
- **Business Rules** — the rules table
- **Actor** — from the frontmatter

From each **T-*.md** extract:
- **Task ID** — T-001, T-002, etc.
- **Task Title** — from the `# {T-ID} — {title}` heading
- **Layer** — from `**Layer:**`
- **Linked Story** — from `**Linked Story:**` — this is the US-ID that this task belongs to
- **Estimate** — from `**Estimate:**`
- **Description** — the description block
- **Acceptance** — the acceptance conditions

Build an inventory before proceeding:

```
Files found in docs/feat/{feature-name}/:

  User Stories:
    US-001.md — {title}   [Actor: {actor}]
    US-002.md — {title}   [Actor: {actor}]

  Tasks:
    T-001.md — {title}   [Layer: {layer}]  [Story: US-001]
    T-002.md — {title}   [Layer: {layer}]  [Story: US-001]
    T-003.md — {title}   [Layer: {layer}]  [Story: US-002]
    ...

  Total: {n} user stories, {n} tasks
```

---

## Step 3 — Resolve Labels, Assignees, and Estimates

### 3.1 Fetch GitLab User IDs

Resolve usernames from CLAUDE.md to real GitLab user IDs:

```
mcp__gitlab__list_project_members(project_id)
```

Match by username or name — store the numeric ID:

```
alice   → gitlab_user_id: 101
bob     → gitlab_user_id: 102
charlie → gitlab_user_id: 103
```

### 3.2 Resolve Estimates to GitLab Weight

| Estimate | GitLab Weight |
|----------|---------------|
| 0.5h | 1 |
| 1h | 1 |
| 2h | 2 |
| 3h | 3 |
| 4h | 4 |
| 5h | 5 |

### 3.3 Assign Labels Per File Type and Layer

**For User Story issues:**

| Story Type | Labels |
|------------|--------|
| All stories | `feature`, `user-story` |

**For Task issues:**

| Layer | Labels |
|-------|--------|
| Data / Entity | `backend`, `db` |
| Repository | `backend`, `db` |
| Application Service | `backend` |
| API / Controller | `backend`, `api` |
| Validation | `backend` |
| Permissions | `backend` |
| Frontend — Page / View | `frontend` |
| Frontend — Component | `frontend` |
| Frontend — State / Integration | `frontend` |
| Notifications | `backend` |
| Integration | `backend`, `api` |
| Config / Migration | `backend`, `db` |
| Testing | `backend` |

Only use labels that exist in `allowed_labels` from CLAUDE.md. Skip any that are not allowed.

### 3.4 Assign Developers

If CLAUDE.md specifies assignment rules per layer — use them.

Otherwise ask the user **once** before creating any issues:

```
No assignment rules found in CLAUDE.md.
Available team members: alice (101), bob (102), charlie (103)

How would you like to assign issues?
1. Assign all to one person
2. Assign by type: user stories → one person, tasks → another
3. Assign by layer (I will list layers and you assign each)
4. Leave all unassigned
```

Store the answer and apply it to every issue — do not ask again per issue.

---

## Step 4 — Check for Existing Issues

Before creating anything, fetch open issues to avoid duplicates:

```
mcp__gitlab__list_issues(project_id, state="opened")
```

For each US-*.md and T-*.md file, check if an issue with a matching title already exists.

- Match found → **update** the existing issue
- No match → **create** new issue

---

## Step 5 — Create User Story Issues First

Post all US-*.md files as GitLab issues **before** any tasks. This is required so task issues can reference their story issue numbers.

### Creation Order

Post in story ID order: US-001, then US-002, then US-003, etc.

### User Story Issue Call

```
mcp__gitlab__create_issue(
  project_id:   {from CLAUDE.md},
  title:        "{US-ID}: {story title}",
  description:  {user story issue description — see template below},
  labels:       ["feature", "user-story", "stage: open"],
  assignee_ids: [{resolved user ID}],
  weight:       0
)
```

**Store the returned GitLab issue number immediately** (e.g. `#10`) — task issues will reference this.

### User Story Issue Description Template

```markdown
## User Story

As a {actor},
I want to {goal},
So that {benefit}.

---

## Scenario 1: Successful flow

Given {condition}
When {action}
Then {result}

---

## Scenario 2: Validation / error flow

Given {condition}
When {action}
Then {result}

---

## Scenario 3: Alternate flow

Given {condition}
When {action}
Then {result}

---

## Acceptance Criteria

{criterion 1}

{criterion 2}

{criterion 3}

---

## Business Rules

| Rule ID | Rule |
|---------|------|
| BR-001 | {rule} |

---

*Source: docs/feat/{feature-name}/{US-ID}.md*
```

---

## Step 6 — Create Task Issues

After all user story issues are created and their GitLab issue numbers are known, post all T-*.md files.

### Creation Order

Post tasks in task ID order: T-001, T-002, T-003, etc.

### Task Issue Call

```
mcp__gitlab__create_issue(
  project_id:   {from CLAUDE.md},
  title:        "{T-ID}: {task title}",
  description:  {task issue description — see template below},
  labels:       [{layer labels}, "stage: open"],
  assignee_ids: [{resolved user ID}],
  weight:       {resolved from estimate}
)
```

### Task Issue Description Template

```markdown
## Task

**Layer:** {layer}
**Estimate:** {estimate}
**Linked User Story:** #{gitlab issue number of the linked US-ID} — {story title}

---

## Description

{description from the task file}

---

## Acceptance

{acceptance conditions from the task file}

---

*Source: docs/feat/{feature-name}/{T-ID}.md*
*User Story: docs/feat/{feature-name}/{US-ID}.md*
```

The `Linked User Story` line must use the real GitLab issue number (e.g. `#10`) obtained in Step 5 — not the US-ID string.

---

## Step 7 — Handle Updates for Existing Issues

When a matching issue was found in Step 4, update it instead of creating a new one:

```
mcp__gitlab__update_issue(
  project_id:   {from CLAUDE.md},
  issue_iid:    {existing issue iid},
  title:        "{ID}: {title}",
  description:  {updated description},
  labels:       [{labels}, "stage: open"],
  assignee_ids: [{resolved user ID}],
  weight:       {weight}
)
```

---

## Step 8 — Print Summary

```
═══════════════════════════════════════════════════════════════════
Feature Files → GitLab Issues Complete
═══════════════════════════════════════════════════════════════════

Feature:     {feature name}
Source:      docs/feat/{feature-name}/
Project ID:  {gitlab project id}

User Story Issues:
  #{n}  US-001 — {title}
  #{n}  US-002 — {title}

Task Issues:
  #{n}  T-001 — {title}   → linked to #{story issue}
  #{n}  T-002 — {title}   → linked to #{story issue}
  #{n}  T-003 — {title}   → linked to #{story issue}
  ...

Summary:
  User Stories posted:  {n}
  Tasks posted:         {n}
  Issues updated:       {n}  (already existed — updated)
  Total issues:         {n}

Validation:
  ✓ All labels valid
  ✓ All assignees resolved

View all issues:
  https://gitlab.com/{namespace}/{repo}/-/issues

═══════════════════════════════════════════════════════════════════
```

---

## Adaptation Rules

| Condition | Behavior |
|-----------|---------|
| CLAUDE.md missing | Ask user for project ID, users, labels before proceeding |
| Label not in allowed list | Skip the label silently, flag in summary |
| Assignee not specified | Ask user once for assignment preference |
| Duplicate issue found | Update existing instead of creating new |
| GitLab MCP unavailable | Output all issues as structured markdown for manual creation |
| US-ID in task file has no matching story issue | Flag in summary — link manually after creation |
| Estimate missing from task file | Default weight to 1, flag in summary |
| Feature folder has no US-*.md files | Stop and report — user stories must be posted before tasks |
