LearnNewsExamplesServices
Frontmatter
id11233
titleExtend create_issue MCP tool with ProjectV2 membership API support + retire release:v13 label hack
stateClosed
labels
enhancementaiarchitecturemodel-experience
assigneesneo-opus-4-7
createdAtMay 11, 2026, 11:49 PM
updatedAtMay 12, 2026, 4:02 AM
githubUrlhttps://github.com/neomjs/neo/issues/11233
authorneo-opus-4-7
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 12, 2026, 4:02 AM

Extend create_issue MCP tool with ProjectV2 membership API support + retire release:v13 label hack

Closedenhancementaiarchitecturemodel-experience
neo-opus-4-7
neo-opus-4-7 commented on May 11, 2026, 11:49 PM

Context

Operator-surfaced 2026-05-11 (this session) on PR #11227 chief-architect audit:

"v13 label are noise. this is NOT how github v2 projects work. tickets have labels and projects. direct api mapping. either we have a ticket to include projects into our create ticket tool, or we already did that. i seriously want to see this hacky label getting removed. not a script to better use the failed approach more."

V-B-A'd: no existing ticket for ProjectV2-in-create_issue. The github-workflow MCP tool's create_issue schema has only title/body/labels/assignees — no addToProjects parameter. The release:v13 label is a hacky workaround for missing project-membership API integration.

The Problem

Current shape (wrong):

  • Agent creates ticket with create_issue({labels: ["release:v13", ...]})
  • release:v13 label is used as project-membership proxy
  • A separate ai/scripts/reconcileV13Project.mjs script reconciles "labeled but not in project" + "in project but not labeled" drift
  • Drift is structural — labels and projects are independent GitHub primitives; the proxy is always going to drift

GitHub Projects v2 reality (per V-B-A on GitHub API docs + the operator's framing):

  • Tickets have LABELS and PROJECTS as independent first-class properties
  • Direct API: addProjectV2ItemById mutation adds a ticket to a project
  • Direct API: removeProjectV2Item mutation removes a ticket from a project
  • No label-as-proxy needed; projects are not derived from labels

Why the current approach was taken (best-guess root cause): create_issue MCP tool was built before ProjectV2 mutation support existed; label was the simplest substrate to add for "v13 release tracking" without extending the tool.

Why it's substrate-failure:

  • Drift between label and project IS structural (PR #11227 V-B-A showed 14 "labeled-not-in-project" + 196 "in-project-not-labeled" — 31% drift)
  • Reconcile script (PR #11227's approach) treats the SYMPTOM (drift detection), not the CAUSE (wrong substrate)
  • Label release:v13 is noise on every ticket — pollutes label-as-categorization-tool semantics
  • PR #11227's pagination fix doesn't fix the substrate; just makes the wrong-shape script more efficient

The Architectural Reality

Per GitHub Projects v2 API:

  • addProjectV2ItemById(input: {projectId: ID!, contentId: ID!}) — adds existing issue to project
  • addProjectV2DraftItem(input: {projectId: ID!, title: String!, body: String}) — creates new draft item

Per Neo MCP tool surface (V-B-A'd):

  • create_issue in ai/mcp/server/github-workflow/openapi.yaml — accepts title/body/labels/assignees only
  • NO addProjectV2* operations exposed
  • NO service file references projectV2 mutation logic

The Fix

Phase 1: Extend create_issue + add project-membership tools

  1. Extend create_issue schema with optional projects parameter:

       projects:
      type: array
      items:
        type: object
        properties:
          projectNumber: { type: integer }
          status: { type: string, description: "Optional initial status (e.g., 'Todo', 'In Progress')" }
      description: |
        (Optional) Array of ProjectV2 memberships to add. Each entry specifies a project number
        and optional initial status. Uses `addProjectV2ItemById` GraphQL mutation after issue creation.
  2. Add manage_issue_projects tool (mirror of manage_issue_labels):

    • action: 'add'addProjectV2ItemById
    • action: 'remove'removeProjectV2Item
    • action: 'update_field'updateProjectV2ItemFieldValue (status, priority, etc.)
  3. Update ticket-create-workflow.md skill payload — replace release:v13 label guidance with projects: [{projectNumber: 12, status: 'Todo'}] pattern.

Phase 2: Retire release:v13 label

  1. Migrate all currently-labeled tickets: add them to ProjectV2 #12 via the new tool, then remove the label
  2. Update all skill payloads that mention release:v13 label to use project-membership pattern instead
  3. Close + retire the release:v13 label from repo settings

Phase 3: Drop reconcile script

  1. ai/scripts/reconcileV13Project.mjs becomes obsolete — drift can't happen if tickets are added directly to project at creation
  2. Delete script + remove npm run ai:reconcile-v13-project from package.json
  3. Close #10961 (pilot ticket) with rationale: pilot proved the wrong-shape approach; correct shape is direct API integration

Acceptance Criteria

  • AC1: create_issue MCP tool schema extended with projects parameter
  • AC2: Service file (ai/services/github-workflow/IssueService.mjs or similar) implements addProjectV2ItemById call after issue creation
  • AC3: New manage_issue_projects tool added with add/remove/update_field actions
  • AC4: ticket-create-workflow.md skill payload updated to use projects parameter instead of release:v13 label
  • AC5: Migration: existing release:v13-labeled tickets added to ProjectV2 #12 + label removed (~68 tickets currently labeled per V-B-A)
  • AC6: release:v13 label retired from repo settings (after AC5)
  • AC7: ai/scripts/reconcileV13Project.mjs deleted + npm run ai:reconcile-v13-project removed from package.json
  • AC8: PR #11227 closed as Drop+Supersede (the pagination fix for a wrong-shape script is no longer needed)
  • AC9: #10961 pilot ticket closed with rationale (pilot proved wrong-shape; this ticket's API integration is the corrective)

Out of Scope

  • General label-as-proxy audit across ALL labels (other labels may have legitimate semantic-categorization use)
  • ProjectV2 list/query tools beyond what's needed for the create_issue + manage_issue_projects scope
  • Cross-org / external-project membership (Neo has one canonical org-level ProjectV2 #12 for v13)

Avoided Traps

  • Patch the reconcile script (PR #11227 approach): rejected — treats symptom not cause; structural drift can't be patched away
  • Use a different label: rejected — labels are wrong-primitive for project membership regardless of name
  • Auto-detect membership from label at runtime: rejected — same as current hack, just hidden in tool implementation
  • Project assignment in agent script (post-create): rejected — racy and partial; create_issue should atomically establish project membership

Related

  • #10961 Pilot GitHub Projects for v13 — proved the wrong-shape approach; this ticket is the corrective
  • #10960 v13 Release Tracking — parent epic; AC tracking depends on accurate project membership
  • PR #11227 pagination fix for the wrong-shape reconcile script — drops on AC8 close
  • PR #11225 / PR #11232 lessons: same §9.0 Premise Pre-Flight failure pattern — mechanical-AC reviews missed architectural-pillar question. Today is the second cluster surfaced.
  • GitHub Projects v2 API: addProjectV2ItemById + removeProjectV2Item

Origin Session ID

c0d5c29d-dc70-44c8-b5af-d3f6c59936ee (operator-surfaced chief-architect friction this session)

Handoff Retrieval Hints

  • query_raw_memories(query="release:v13 label hack ProjectV2 API create_issue project membership")
  • ask_knowledge_base(query="github projects v2 api ticket membership label proxy")
  • File anchors: ai/mcp/server/github-workflow/openapi.yaml (create_issue schema), ai/services/github-workflow/IssueService.mjs (implementation), .agents/skills/ticket-create/references/ticket-create-workflow.md (skill guidance)

🤖 Generated with Claude Code

tobiu referenced in commit ea3af10 - "feat(github-workflow): extend create_issue with projects param + add manage_issue_projects tool (#11233) (#11234) on May 12, 2026, 4:02 AM
tobiu closed this issue on May 12, 2026, 4:02 AM
tobiu referenced in commit 5dcf6ef - "chore(ai/scripts): Add Phase 2 ProjectV2 migration script (#11233) (#11246) on May 12, 2026, 10:11 AM
tobiu referenced in commit 2b4f630 - "chore: remove obsolete reconcileV13Project script (#11233) (#11247) on May 12, 2026, 10:12 AM
tobiu referenced in commit 774b1b5 - "chore: remove obsolete migrateV13ProjectFromLabel script (#11233) (#11251) on May 12, 2026, 12:31 PM