> ## Documentation Index
> Fetch the complete documentation index at: https://haico.gr/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Copilot automation (background)

> The original Copilot-based design for the AI pathway, kept as background.

# GitHub Issues + Projects ↔ Copilot Coding Agent: End-to-End Automation

> **Status: background, not as-built.** The repo adopted a **provider-agnostic**
> implementation that runs the coding agent via [GitHub Agentic Workflows
> (`gh-aw`)](https://github.github.com/gh-aw/) on the repository's own API key,
> **not** the GitHub Copilot Coding Agent, so any maintainer with write access
> can drive it without a Copilot seat (see [ADR-0002](/docs/adr/0002-dual-development-pathways)).
> The canonical, as-built description is **[ai-pathway.md](/docs/ai-pathway)**; where
> the two differ, that document wins. Notable deviations from the design below:
> the `ai:improve-writing` button was dropped; "assign to `Copilot`" became
> "add `path:ai-automation` → agent posts a plan → `/approve-plan`"; the
> `@copilot` iteration loop became the `/coco` slash command (gh-aw has no
> `@mention` trigger); and notifications are GitHub @-mentions rather than email.
> This document is retained for the design rationale and the broader landscape (§10).

This document describes an automation that turns a GitHub Issue into a deployed dev build with minimal human steps, **entirely inside GitHub** (no external tracker, no external orchestrator). The implementer is **GitHub Copilot Coding Agent**; the orchestrator is **GitHub Actions**; the human-facing "buttons" are **issue labels**, **GitHub Project status columns**, and **slash commands** in issue/PR comments. The visual board is a **GitHub Project (v2)** attached to the repo.

The design satisfies four constraints:

1. Every step of the lifecycle is recorded as a comment on a single GitHub issue and as a status change on the Project board; together they are the audit log.
2. All AI instructions (system prompts, persistent agent rules, per-flow prompts) live **in this repository**, version-controlled and reviewable in PRs.
3. The reviewer can talk back to Copilot by `@copilot`-mentioning it on the PR. Copilot replies, pushes new commits, and CI re-runs. No custom backend is needed for the iteration loop; GitHub provides it natively.
4. The existing CI pipeline (semver tags → `dev-vX.Y.Z` → dev environment) is kept as-is. The automation only *triggers* it; it does not replace it.

Because everything stays inside GitHub, the design is deliberately simple: no cross-system tokens, no web-request plumbing, no custom-field ID mapping, no mirror workflow. The GitHub Issue *is* the work item.

***

## 1. High-level flow

```mermaid theme={null}
flowchart TD
    A["GitHub Issue, new<br/>Project status: Backlog<br/>human files an issue with a rough description, or via an issue form"]
    A -->|"1 · human adds label ai:improve-writing"| B["Action improve-issue.yml<br/>fires on labeled, calls LLM with prompts/improve-issue.md<br/>rewrites issue body via gh issue edit, removes label, posts an audit comment"]
    B -->|"2 · human assigns the issue to Copilot, or sets Project status to Ready for AI, which a workflow translates to assignment"| C["Copilot Coding Agent reads AGENTS.md and path-scoped .github/instructions/*<br/>opens a draft PR on a copilot/issue-n branch<br/>runs tests, pushes commits"]
    C -->|"Project automation moves the linked issue to In Progress"| D["ci.yml runs on the PR"]
    D -->|"3 · automatic on CI green"| E["Workflow ai-review-pr.yml<br/>runs an LLM review using prompts/review-pr.md"]
    E -->|"4 · human PR comment: /promote dev"| F["promote-dev.yml pushes dev-vX.Y.Z tag<br/>existing ci.yml deploy job runs"]
    F -->|"5 · on deploy success: workflow sets Project status to On Dev and emails reviewer"| G["Reviewer tests dev env<br/>if problem, reviewer writes @copilot fix X on the PR; Copilot revises, CI re-runs<br/>if approved, PR merges, issue auto-closes, Project status to Done, email to author"]
```

Every transition writes a comment back to the originating issue *and* updates the issue's row on the Project board.

***

## 2. Why this shape

* **Copilot Coding Agent is the implementer.** When an issue is assigned to Copilot, it provisions a sandboxed VM, clones the repo, reads the agent instructions, opens a draft PR, and iterates until tests pass. The feedback loop is built in: a comment that mentions `@copilot` on the PR is treated as a new instruction, and Copilot preserves PR history as context. That loop does **not** need to be built separately.
* **GitHub Actions is the orchestrator**, not a separate backend service. Each "button" is either an `issues: labeled` workflow, an `issue_comment` workflow, or (rarely) a `projects_v2_item` workflow. Secrets live in GitHub Secrets; there is no extra host to operate and no cross-system token.
* **All prompts live in the repo** (`.github/prompts/`, `AGENTS.md`, `.github/instructions/`). They are reviewed in PRs and rollback is `git revert`.
* **The Project (v2) is the visual board.** It is GitHub-native, supports custom fields and saved views, and has built-in automations for the obvious transitions (issue closed → Done, PR merged → Done). For more nuanced transitions, an Action calls the GraphQL `updateProjectV2ItemFieldValue` mutation.
* **The existing CI tag-based deploy is the deploy mechanism.** `promote-dev.yml` only creates the tag; `ci.yml` does the rest.

> **Native Copilot integration.** This document assumes a GitHub Copilot plan that grants the Copilot Coding Agent. Assigning an issue to the `Copilot` user is the *only* trigger Copilot needs to start work (no app install, no webhook setup). The trigger is already in GitHub.

***

## 3. Repository + Project layout

Everything the automation needs is in `.github/` and a single GitHub Project attached to the repo (or to the org):

```mermaid theme={null}
flowchart TD
    ROOT[".github/"]
    ROOT --> AGENTS["AGENTS.md · persistent rules read by Copilot every run"]
    ROOT --> COPILOT["copilot-instructions.md · same purpose, Copilot-specific fallback"]
    ROOT --> PRT["pull_request_template.md · exists, used by Copilot when opening PRs"]
    ROOT --> ISSUE["ISSUE_TEMPLATE/ · exists, used by humans to file issues"]
    ROOT --> INSTR["instructions/ · path-scoped agent rules"]
    ROOT --> PROMPTS["prompts/ · one-shot prompts used by orchestration workflows"]
    ROOT --> WF["workflows/"]
    ROOT --> AUTO["automation/"]

    ISSUE --> FR["feature_request.yml · YAML issue form, structured fields"]
    ISSUE --> BR["bug_report.yml · YAML issue form"]

    INSTR --> BE["backend.instructions.md · applies to backend/**"]
    INSTR --> FE["frontend.instructions.md · applies to frontend/**"]

    PROMPTS --> P1["improve-issue.md"]
    PROMPTS --> P2["refine-acceptance-criteria.md"]
    PROMPTS --> P3["review-pr.md"]
    PROMPTS --> P4["triage-issue.md · optional, see §10.B.1"]

    WF --> W1["ci.yml · exists, lint, test, build, deploy"]
    WF --> W2["branch-name.yml · exists"]
    WF --> W3["improve-issue.yml · NEW: button 1, label-triggered"]
    WF --> W4["assign-to-copilot.yml · NEW: button 2, label or status change"]
    WF --> W5["ai-review-pr.yml · NEW: auto-review after CI green"]
    WF --> W6["promote-dev.yml · NEW: /promote dev comment to dev tag"]
    WF --> W7["notify-on-approve.yml · NEW: PR approval to email user"]
    WF --> W8["project-status-sync.yml · NEW: updates the Project's Status field"]

    AUTO --> CFG["config.yml · model names, label names, Project node IDs"]
```

### What goes where, conceptually

| File / directory                         | Read by                 | When                         | Purpose                                                                        |
| ---------------------------------------- | ----------------------- | ---------------------------- | ------------------------------------------------------------------------------ |
| `AGENTS.md`                              | Copilot Coding Agent    | Every implementation run     | Persistent project rules (style, no-secrets, dependency policy, …).            |
| `.github/instructions/*.instructions.md` | Copilot Coding Agent    | When touching matching paths | Layer-specific rules (e.g. "use FastAPI's dependency injection, not globals"). |
| `.github/prompts/*.md`                   | Orchestration workflows | When that workflow runs      | Templated prompts for non-Copilot LLM calls (issue rewrite, PR review, …).     |
| `.github/automation/config.yml`          | All workflows           | At workflow start            | Single source of truth for model IDs, label names, Project + field node IDs.   |
| GitHub Project (v2)                      | Humans + sync workflow  | Continuously                 | Visual board, status field, custom fields (Reviewer, Dev URL, PR URL).         |

> The `.prompt.md` and `.agent.md` filename conventions are reserved for IDE/CLI chat; they are not used here. This repo uses plain `.md` files invoked by workflows, which gives full control over the body.

***

## 4. The seven manual triggers

Every trigger is a native GitHub gesture:

| # | "Button" the human uses    | Mechanism                                                              | Effect                                                                 |
| - | -------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| 1 | Improve issue writing      | Add label `ai:improve-writing` to the issue                            | Workflow rewrites the issue body in place; removes the label.          |
| 2 | Hand to Copilot            | Assign the issue to `Copilot` (or set Project status → "Ready for AI") | Copilot opens a draft PR. Project auto-moves the row to "In Progress". |
| 3 | Request automated review   | Add label `ai:review` to the PR (also auto on CI green)                | Workflow posts an AI review on the PR.                                 |
| 4 | Promote to dev             | PR comment `/promote dev`                                              | Creates `dev-vX.Y.Z` tag; CI deploys.                                  |
| 5 | Notify reviewer            | Automatic after dev deploy success                                     | Email to the user named in the Project's *Reviewer* field.             |
| 6 | Notify me (final review)   | Automatic on PR `approved` review                                      | Email to the issue author.                                             |
| 7 | Apply reviewer instruction | PR comment `@copilot …`                                                | Copilot natively revises.                                              |

Triggers 1 and 3 use **labels as buttons**: adding the label is the user's action, and the workflow's first step is to *remove* the label so it can be re-added later. Triggers 4 and 7 use **slash/mention commands** in PR comments, which read naturally in the review thread. Trigger 2 uses the native **assign** field, which is the single trigger the Copilot Coding Agent listens for.

Trigger 7 deliberately bypasses the orchestration: Copilot's own iteration loop is the simplest, most reliable way to apply a reviewer's instruction with full history.

***

## 5. Step-by-step setup

### Step 5.1: Decide on the Project shape

Create a GitHub Project (v2), either at the org or user level, and attach it to this repo. Add these custom fields:

* **Status** (single-select, built-in): `Backlog`, `Ready for AI`, `In Progress`, `Review`, `On Dev`, `Approved`, `Done`.
* **AI Status** (single-select, optional): `Idle`, `Improving`, `Implementing`, `Reviewing`, `On Dev`. Useful for a *concurrent* field separating human progress from AI progress on the same row.
* **Reviewer** (User picker): drives email notifications.
* **Dev URL** (URL).
* **PR URL** (URL): also auto-filled when an issue is linked to a PR via "Development" sidebar.
* **Sprint / Iteration** (Iteration field, optional).

Suggested **views** on the board:

1. **Triage**: filter `Status = Backlog`. Where humans land new issues.
2. **AI queue**: filter `Status in (Ready for AI, In Progress)`. Where Copilot's work is watched.
3. **Review on dev**: filter `Status = On Dev`. Reviewer's queue.
4. **Released**: filter `Status = Done`, group by iteration.

Configure the Project's **built-in workflows** (Project → Settings → Workflows):

* *Item added to project* → set `Status = Backlog`.
* *Pull request merged* → set `Status = Done`.
* *Issue closed* → set `Status = Done`.
* *Code changes requested on PR* → set `Status = In Progress`.

These cover the obvious transitions for free. The non-obvious transitions (*Ready for AI* → *In Progress* on PR open, *In Progress* → *On Dev* on dev deploy) are handled by `project-status-sync.yml` (§5.11) using the GraphQL API.

There is no need to model every status as a hard state machine; most transitions are advisory and the workflows reconcile them.

### Step 5.2: Configure repository permissions for Actions

Because every trigger fires from inside GitHub, the workflows can use the default `GITHUB_TOKEN`. It just needs enough scope granted.

In **Settings → Actions → General → Workflow permissions**:

* Choose *Read and write permissions*.
* Allow GitHub Actions to *create and approve pull requests*.

Per-workflow, declare the minimum scopes (always prefer this over the global toggle once things are stable):

```yaml theme={null}
permissions:
  issues: write          # edit issue body, comment, label
  pull-requests: write   # comment, label
  contents: write        # push tags from promote-dev.yml only
```

For Projects (v2), the **default `GITHUB_TOKEN` cannot write to org-owned projects**. If the Project is org-owned, create a fine-grained PAT for a service account with `Projects: read & write` on the relevant org, store it as the repo secret `PROJECTS_TOKEN`, and reference it from `project-status-sync.yml`. If the Project is user-owned and attached to this repo only, `GITHUB_TOKEN` is sufficient.

### Step 5.3: Add LLM + notification secrets

The only secrets required are:

* `OPENAI_API_KEY` (or `ANTHROPIC_API_KEY`): for the LLM calls in workflows.
* `SENDGRID_API_KEY` (or `SMTP_*`): for notification emails.
* `PROJECTS_TOKEN`: only if the Project is org-owned (§5.2).

Note that no cross-system credentials are needed. That entire surface area is gone.

### Step 5.4: Write the persistent agent instructions

Create [`AGENTS.md`](https://github.com/petrosrapto/HAICO/blob/main/.github/AGENTS.md) at `.github/AGENTS.md`. This is the file Copilot reads on **every** implementation run. Keep it short and load-bearing.

```markdown theme={null}
# Repository agent instructions

## Project shape
- Monorepo: `backend/` (FastAPI), `frontend/` (Next.js), `deployment/`.
- PRs must target `develop`, never `main`.

## Coding rules
- Backend: type-hint all new functions. Use FastAPI dependency injection.
- Frontend: TypeScript only; no `any`.
- Never commit secrets. `.env*` files are gitignored; do not unignore them.

## Test rules
- Backend: pytest. New endpoints require a happy-path test.
- Frontend: lint must pass (`npm run lint`).

## Out of scope
- Do not modify `.github/workflows/ci.yml` or `deployment/` files unless the
  issue explicitly says so.
```

Add path-scoped instructions for finer-grained rules:

```
.github/instructions/backend.instructions.md
.github/instructions/frontend.instructions.md
```

Each should have YAML frontmatter declaring its scope:

```markdown theme={null}
---
applyTo: "backend/**"
---
- Use the existing `backend/app/llm/` factory; do not call provider SDKs directly from routes.
- Database access must go through `backend/app/db/` repositories.
```

### Step 5.5: Write the one-shot prompts

Each file in `.github/prompts/` is a Markdown template with placeholders the workflow substitutes at runtime. Example `improve-issue.md`.

```markdown theme={null}
You are rewriting a GitHub issue so engineers can act on it.

Rules:
- Preserve the original intent. Do not invent requirements.
- Output sections in this exact order: ## Context, ## Goal, ## Acceptance criteria, ## Out of scope.
- Acceptance criteria must be a checklist of testable statements.
- Preserve any "Linked PR" or "Related issues" trailers at the bottom.

## Original issue
Title: {{title}}

Body:
{{body}}
```

Repeat for `review-pr.md` (review prompt fed the PR diff) and any other one-shot LLM operation as needed.

### Step 5.6: Workflow: improve issue writing (label-triggered)

`.github/workflows/improve-issue.yml`:

```yaml theme={null}
name: Improve issue writing
on:
  issues:
    types: [labeled]

jobs:
  improve:
    if: github.event.label.name == 'ai:improve-writing'
    runs-on: ubuntu-latest
    permissions:
      issues: write
    steps:
      - uses: actions/checkout@v4

      - name: Render prompt + call LLM + edit issue
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          ISSUE_TITLE:  ${{ github.event.issue.title }}
          ISSUE_BODY:   ${{ github.event.issue.body }}
        run: |
          python .github/scripts/improve_issue.py

      - name: Remove the trigger label
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh issue edit "${{ github.event.issue.number }}" \
            --remove-label "ai:improve-writing"
```

Companion script `.github/scripts/improve_issue.py` reads `.github/prompts/improve-issue.md`, substitutes placeholders, calls the LLM, and runs `gh issue edit "$ISSUE_NUMBER" --body-file <(...)`. It also posts a comment with the diff against the previous body so the audit log is preserved.

**Why a label and not a slash command?** A label is visible in the issue sidebar, can be added from mobile, and is reflected on the Project board as a filterable property. Slash commands are great for PRs but slightly hidden on issues.

### Step 5.7: Hand the issue to Copilot

There are two equally good UX choices; either can be picked, or both supported.

**Option A: Direct assignment (recommended).** The human opens the issue and sets the *Assignees* field to `Copilot`. That is the only trigger the Copilot Coding Agent needs. No workflow required.

**Option B: Status-driven.** The human drags the row on the Project board to *Status = Ready for AI*. A workflow (`assign-to-copilot.yml`) listens to `projects_v2_item` events, sees the status change, and runs `gh issue edit --add-assignee Copilot`. This is the nicer board-driven UX but costs an extra workflow.

`.github/workflows/assign-to-copilot.yml` (Option B):

```yaml theme={null}
name: Assign issue to Copilot when ready
on:
  # `projects_v2_item` is available on repos linked to org-owned Projects.
  # If your Project is user-owned, use Option A or a `workflow_dispatch` shim.
  projects_v2_item:
    types: [edited]

jobs:
  assign:
    runs-on: ubuntu-latest
    permissions:
      issues: write
    steps:
      - name: Check if this edit moved the item to "Ready for AI"
        id: gate
        uses: actions/github-script@v7
        with:
          script: |
            const change = context.payload.changes?.field_value;
            if (!change) return core.setOutput('go', 'false');
            const moved = change.from?.name !== 'Ready for AI'
                       && change.to?.name === 'Ready for AI';
            core.setOutput('go', moved ? 'true' : 'false');
      - name: Resolve linked issue and assign Copilot
        if: steps.gate.outputs.go == 'true'
        env:
          GH_TOKEN: ${{ secrets.PROJECTS_TOKEN || secrets.GITHUB_TOKEN }}
        run: |
          python .github/scripts/assign_to_copilot.py \
            --item-id "${{ github.event.projects_v2_item.node_id }}"
```

The script resolves the linked Issue node, then runs `gh issue edit "$NUMBER" --add-assignee Copilot`. When the issue is assigned to `Copilot`, Copilot spins up a sandboxed environment, reads `AGENTS.md`, opens a draft PR on `copilot/issue-<n>`, and begins committing. No workflow is needed for that step; the assignment is the trigger.

### Step 5.8: Workflow: AI review after CI passes

`.github/workflows/ai-review-pr.yml` runs when CI completes successfully on a PR (or when the `ai:review` label is added for an on-demand re-review):

```yaml theme={null}
name: AI review PR
on:
  workflow_run:
    workflows: ["CI"]
    types: [completed]
  pull_request:
    types: [labeled]

jobs:
  review:
    if: |
      (github.event_name == 'workflow_run' &&
       github.event.workflow_run.conclusion == 'success' &&
       github.event.workflow_run.event == 'pull_request')
      ||
      (github.event_name == 'pull_request' &&
       github.event.label.name == 'ai:review')
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.workflow_run.head_sha || github.event.pull_request.head.sha }}
      - run: python .github/scripts/ai_review.py \
               --pr-sha "${{ github.event.workflow_run.head_sha || github.event.pull_request.head.sha }}" \
               --prompt .github/prompts/review-pr.md
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
```

The script fetches the PR diff, renders the prompt, calls the LLM, posts a **review comment** (not an approval) summarising risks and suggested changes. Approval stays human.

### Step 5.9: Workflow: `/promote dev` comment → dev tag

`.github/workflows/promote-dev.yml`:

```yaml theme={null}
name: Promote to dev
on:
  issue_comment:
    types: [created]

jobs:
  promote:
    if: |
      github.event.issue.pull_request &&
      startsWith(github.event.comment.body, '/promote dev') &&
      contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'),
               github.event.comment.author_association)
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Compute next dev tag
        id: tag
        run: |
          # naive bump: replace with your conventional-commits / semver script
          LAST=$(git tag --list 'dev-v*' --sort=-v:refname | head -n1 || echo dev-v0.0.0)
          NEXT=$(echo "$LAST" | awk -F. -v OFS=. '{$NF+=1; print}')
          echo "name=$NEXT" >> $GITHUB_OUTPUT
      - name: Push tag
        run: |
          git tag "${{ steps.tag.outputs.name }}"
          git push origin "${{ steps.tag.outputs.name }}"
      - name: Acknowledge in PR thread
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh pr comment "${{ github.event.issue.number }}" \
            --body "Tag \`${{ steps.tag.outputs.name }}\` pushed. Dev deploy starting."
```

Because the existing `ci.yml` already deploys on `dev-vX.Y.Z` tags, that is the entire dev-promotion step.

> **Permission gate.** The `author_association` check restricts who can run `/promote dev`; otherwise anyone with read access could trigger a deploy. Tighten further with a team check via `gh api /orgs/.../teams/.../members` to restrict the power to a specific team.

### Step 5.10: Workflow: notify on approval

`.github/workflows/notify-on-approve.yml` listens for `pull_request_review` events of type `approved` and sends the email:

```yaml theme={null}
name: Email author on PR approval
on:
  pull_request_review:
    types: [submitted]

jobs:
  notify:
    if: github.event.review.state == 'approved'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: python .github/scripts/notify_author.py \
               --pr-number "${{ github.event.pull_request.number }}" \
               --author "${{ github.event.pull_request.user.login }}"
        env:
          SENDGRID_API_KEY: ${{ secrets.SENDGRID_API_KEY }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

Read recipient addresses from `.github/automation/config.yml` (mapped from the GitHub login of the author) or, better, from the Project's *Reviewer* field via GraphQL; that way the recipient is whatever the human set on the row.

### Step 5.11: Configure Project automations (the human side)

Most of the Project board's behavior comes from its **built-in workflows** (set up in Step 5.1). The remaining transitions are handled by `.github/workflows/project-status-sync.yml`, which reacts to GitHub events and writes back to the Project via GraphQL:

| Event                            | Status set to | Notes                                                                                       |
| -------------------------------- | ------------- | ------------------------------------------------------------------------------------------- |
| Issue assigned to `Copilot`      | `In Progress` | (only if Copilot then opens a draft PR within \~2 min; otherwise stays at the prior status) |
| PR labeled `ai:review`           | `Review`      | Manual override.                                                                            |
| `dev-vX.Y.Z` tag deploy succeeds | `On Dev`      | Resolves PR from tag's commit.                                                              |
| PR reviewed & approved           | `Approved`    |                                                                                             |
| PR merged                        | `Done`        | Also covered by built-in workflow.                                                          |

Skeleton workflow:

```yaml theme={null}
name: Sync Project status
on:
  issues:
    types: [assigned]
  pull_request:
    types: [labeled]
  pull_request_review:
    types: [submitted]
  workflow_run:
    workflows: ["CI"]   # to catch dev deploys
    types: [completed]

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: python .github/scripts/project_status_sync.py
        env:
          GH_TOKEN: ${{ secrets.PROJECTS_TOKEN || secrets.GITHUB_TOKEN }}
          PROJECT_ID:        ${{ vars.PROJECT_ID }}
          STATUS_FIELD_ID:   ${{ vars.STATUS_FIELD_ID }}
          STATUS_OPTION_IDS: ${{ vars.STATUS_OPTION_IDS }}   # JSON map
```

`PROJECT_ID`, `STATUS_FIELD_ID`, and the option IDs are resolved once via the GraphQL Explorer (or `gh api graphql -f query='…'`) and stored as repo variables. They do not rotate.

The script uses the `updateProjectV2ItemFieldValue` GraphQL mutation:

```graphql theme={null}
mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
  updateProjectV2ItemFieldValue(input: {
    projectId: $projectId,
    itemId:    $itemId,
    fieldId:   $fieldId,
    value:     { singleSelectOptionId: $optionId }
  }) {
    projectV2Item { id }
  }
}
```

***

## 6. The Copilot loop in detail

Once the issue is assigned to Copilot:

1. Copilot creates branch `copilot/issue-<n>` and opens a **draft PR** using [`.github/pull_request_template.md`](https://github.com/petrosrapto/HAICO/blob/main/.github/pull_request_template.md).
2. Copilot reads `AGENTS.md`, then the relevant `.github/instructions/*.instructions.md` files based on which paths it is about to touch.
3. Copilot iterates internally: write → run tests → diagnose → revise. Each iteration pushes a commit, which appears as a comment-like entry in the PR timeline.
4. `ci.yml` runs on each push because of the existing `pull_request` trigger.
5. When the agent believes it is done, it **marks the PR ready for review** and posts a summary comment.

To send feedback, a reviewer comments on the PR (not the issue):

```
@copilot the dev container failed health-check at /api/health.
The cause looks like a missing env var. Please add a default to settings.py
and a test that covers the missing-env path.
```

Copilot picks up the mention, treats the entire PR thread + AGENTS.md as context, and pushes new commits. Nothing needs to be dispatched manually.

***

## 7. Optional: structured input via Issue Forms

A free-text issue body is fine, but **issue forms** (`.github/ISSUE_TEMPLATE/*.yml`) give Copilot cleaner context. Example `feature_request.yml`:

```yaml theme={null}
name: Feature request
description: Ask Copilot to implement a feature
title: "[feat] "
labels: ["enhancement"]
body:
  - type: textarea
    id: context
    attributes:
      label: Context
      description: What is the user need, and what is the current behavior?
    validations:
      required: true
  - type: textarea
    id: goal
    attributes:
      label: Goal
      description: One sentence describing what success looks like.
    validations:
      required: true
  - type: textarea
    id: acceptance
    attributes:
      label: Acceptance criteria
      description: Checklist of testable statements. Copilot will use these.
      placeholder: |
        - [ ] Endpoint `POST /foo` returns 201 with the new id
        - [ ] Unit test covers the missing-field error path
    validations:
      required: true
  - type: input
    id: out_of_scope
    attributes:
      label: Out of scope
```

When the human fills the form, the resulting issue body has predictable sections, so the *improve-issue* workflow rarely needs to run, and Copilot can parse the acceptance criteria directly.

***

## 8. Things that are deliberately **not** in scope

* **A FastAPI orchestrator.** Adding one is justified if the project later needs cross-repo orchestration, long-running jobs >6h, or non-GitHub destinations (Slack threads, custom dashboards). Until then, Actions is enough.
* **Auto-approval by AI.** `ai-review-pr.yml` posts a *comment*, never an approval. The human gate is non-negotiable for merges to `develop`.
* **Status as a hard state machine.** The Project's *Status* field is a convenience for humans, not a contract. Workflows do not block on it being in a particular state; they react to the underlying GitHub events.
* **Mirroring to external systems.** The whole point of this variant is that the issue + PR + Project board are the audit log. No mirror layer.

***

## 9. Open decisions to make

1. **Hand-off UX.** Option A (assign to `Copilot`) is simpler and works without `projects_v2_item` permissions. Option B (drag on the board) is nicer for teams that live on the board. Both can be supported; they are not exclusive.
2. **Which LLM provider for the non-Copilot calls.** OpenAI, Anthropic, or Google. Pick one and set it in `.github/automation/config.yml`.
3. **Tag-naming for dev promotions.** The existing CI expects strict `dev-vX.Y.Z`. Decide whether `/promote dev` bumps PATCH automatically or whether the comment must include the version: `/promote dev v1.2.3`.
4. **Permission policy for `/promote dev`.** Restrict to `OWNER`/`MEMBER` (default in the example), or to a specific GitHub team.
5. **Project scope (user vs. org).** Org-owned Projects support `projects_v2_item` events but require the `PROJECTS_TOKEN` PAT for writes. User-owned Projects skip the PAT but lose the event-driven status updates, falling back to polling or label-based triggers.
6. **Issue forms vs. free-text.** Strongly recommended to use forms; they make §5.6's *improve-issue* workflow optional.

Once these are decided, the files can be scaffolded and issues labelled one by one.

***

## 10. The broader GitHub AI automation landscape

The GitHub-only Issue → Copilot loop is one slice of what GitHub now ships. This section catalogues the rest so the doc gives a holistic picture, and notes which ones are worth turning on for this repo.

Each item is tagged:

* **Turn on**: clear ROI for this repo, low setup cost.
* **Consider**: useful but adds operational surface; pick when there's a need.
* **Watch**: preview / early-stage; revisit later.

### A. Native integrations worth enabling

#### A.1. GitHub Copilot code review  *(Turn on)*

A built-in PR-review feature, distinct from this repo's custom `ai-review-pr.yml`. Two modes:

* **On-demand:** request a review from `Copilot` in the PR reviewers panel.
* **Automatic:** configure Copilot to review every PR opened in selected repos (Repository → Rulesets → branch ruleset, or in user settings for personal Copilot Pro).

What it does well: catches obvious bugs, style issues, missing null-checks, suggests fixes inline. What it does **not** do: domain-specific architecture review against the `AGENTS.md` rules. That's what the custom `ai-review-pr.yml` prompt is for. **Recommendation: run both.** The native review is free with the Copilot plan; the custom review is where HAICO-specific constraints are encoded.

#### A.2. CodeQL + Copilot Autofix  *(Turn on)*

CodeQL is GitHub's static-analysis engine (free for public repos, included with GitHub Advanced Security on private). Copilot Autofix turns each CodeQL finding into a suggested patch that can be merged with one click. Together they cover the "security review" leg without a custom workflow.

Setup: Settings → Code security → enable *CodeQL analysis* (default config) and *Copilot Autofix for CodeQL*. Findings appear in the *Security* tab and as PR review comments.

#### A.3. Dependabot  *(already on)*

This repo already has `.github/dependabot.yml`. The AI layer worth adding here is **Dependabot's grouped updates + Copilot Autofix for vulnerable dependencies**, which can land a tested upgrade PR with no human-authored code.

#### A.4. Secret scanning + push protection  *(Turn on)*

GitHub-native, free for public repos. Push protection blocks commits that contain known secret patterns *before* they reach the remote, an important guardrail when Copilot has write access to the branch.

#### A.5. Project built-in workflows  *(Turn on)*

Already used in §5.1. Worth flagging here as a reminder: the *Item added*, *Auto-close issue*, *Auto-archive items*, and *Pull request merged* automations cover \~60% of the Project transitions that would otherwise need scripting. Reach for the custom `project-status-sync.yml` only for the rest.

> There is *no* issue-creation workflow in this design, because the issue is filed directly in GitHub.

### B. New surface area for AI-driven workflows

#### B.1. Agentic Workflows (`gh-aw`)  *(Consider: technical preview)*

Released as a technical preview in February 2026. A workflow is written as a Markdown file with natural-language instructions and a frontmatter declaring inputs / tools / triggers; the `gh aw compile` CLI emits a hardened `*.lock.yml` GitHub Actions workflow that runs an AI agent (Copilot, Claude, or Codex) in a sandboxed container.

Example use cases that fit this repo:

* *Triage incoming issues*: read the issue, apply labels (`needs-info`, `bug`, `enhancement`), ask for missing reproduction info. **Especially useful in the GitHub-only flow** since there is no upstream layer to do triage.
* *Generate a changelog* for each `dev-vX.Y.Z` tag from the commit range.
* *Refresh documentation* when files in `backend/app/api/` change.
* *Project hygiene*: sweep the Project board weekly, flag stale items, ask authors for status.

When to use it instead of writing Actions directly: when the task is underspecified, the inputs vary, and the agent should decide what to do. When to *not* use it: deterministic glue (creating an issue, posting a comment, pushing a tag); plain Actions are clearer and cheaper.

#### B.2. GitHub Copilot Spaces  *(Consider)*

GA since 2025. A *Space* is a shareable container of repos + docs + free text + behavioural instructions that Copilot uses as grounding context. A Space is useful when knowledge sits **outside** the repo (e.g. a Notion export of architecture decisions, transcripts of design reviews, third-party API specs) and should be considered by Copilot in chat.

For HAICO specifically: a "HAICO architecture" Space attached to this repo, with the project's design/reference documents attached, would make Copilot answer architecture questions with paper-aware context, without adding those documents to the repo's text-search index.

#### B.3. MCP servers (Model Context Protocol)  *(Consider for advanced flows)*

MCP lets an agent call external tools as if they were local functions. Copilot in VS Code, CLI, and the cloud agent can all consume MCP servers. Relevant catalog for a GitHub-only flow:

| MCP server          | Lets the agent…                                          |
| ------------------- | -------------------------------------------------------- |
| GitHub MCP          | call any GitHub API operation, not just the wrapped ones |
| Sentry / Datadog    | pull error traces while debugging                        |
| Postgres / Supabase | run read-only queries against a dev DB                   |
| Linear / Notion     | only if one is adopted later, none currently in scope    |

MCP servers are configured per-environment (e.g. `.vscode/mcp.json` for the IDE; the Copilot Coding Agent has its own configuration UI). For this scope, the GitHub server covers \~90% of value because the rest of the world lives outside this stack anyway.

#### B.4. GitHub Spark  *(Watch)*

GitHub's prompt-to-app builder. Out of scope for an established repo; it's better suited to generating new prototypes. Worth knowing about when sketching a sibling demo app.

### C. Things to enforce in the repo's structure

Independent of any product, these are conventions that make every AI feature work better:

* **`AGENTS.md` at the repo root**: already in the plan (§5.4). This is the single highest-leverage file that can be added.
* **`.github/instructions/*.instructions.md`** with `applyTo:` frontmatter for per-area rules (backend/frontend/deployment).
* **Issue forms** (`.github/ISSUE_TEMPLATE/*.yml`): see §7. The GitHub-only flow leans hard on these, because they serve as the structured input.
* **CODEOWNERS** mapping paths to humans: Copilot uses this to choose reviewers when opening PRs, and the Project's *Reviewer* field can default from this mapping.
* **ADRs** (Architecture Decision Records) under `docs/adr/`: Copilot reads them as context for architecture-touching changes.

***

## 11. Sources

* [Assigning and completing issues with coding agent in GitHub Copilot (GitHub Blog)](https://github.blog/ai-and-ml/github-copilot/assigning-and-completing-issues-with-coding-agent-in-github-copilot/)
* [About GitHub Copilot cloud agent (GitHub Docs)](https://docs.github.com/copilot/concepts/agents/coding-agent/about-coding-agent)
* [Adding repository custom instructions for GitHub Copilot (GitHub Docs)](https://docs.github.com/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot)
* [Copilot coding agent now supports AGENTS.md (GitHub Changelog)](https://github.blog/changelog/2025-08-28-copilot-coding-agent-now-supports-agents-md-custom-instructions/)
* [Ask @copilot to make changes to any pull request (GitHub Changelog)](https://github.blog/changelog/2026-03-24-ask-copilot-to-make-changes-to-any-pull-request/)
* [About Projects (GitHub Docs)](https://docs.github.com/en/issues/planning-and-tracking-with-projects/learning-about-projects/about-projects)
* [Automating Projects using Actions (GitHub Docs)](https://docs.github.com/en/issues/planning-and-tracking-with-projects/automating-your-project/automating-projects-using-actions)
* [Using the API to manage Projects (GitHub Docs)](https://docs.github.com/en/issues/planning-and-tracking-with-projects/automating-your-project/using-the-api-to-manage-projects)
* [Workflow events: `projects_v2_item` (GitHub Docs)](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#projects_v2_item)
* [Syntax for issue forms (GitHub Docs)](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms)
* [About GitHub Copilot code review (GitHub Docs)](https://docs.github.com/en/copilot/concepts/agents/code-review)
* [Configuring automatic code review by Copilot (GitHub Docs)](https://docs.github.com/en/copilot/using-github-copilot/code-review/configuring-automatic-code-review-by-copilot)
* [About GitHub Copilot Spaces (GitHub Docs)](https://docs.github.com/en/copilot/concepts/context/spaces)
* [GitHub Agentic Workflows (Documentation)](https://github.github.com/gh-aw/)
* [GitHub Agentic Workflows are now in technical preview (GitHub Changelog)](https://github.blog/changelog/2026-02-13-github-agentic-workflows-are-now-in-technical-preview/)
* [github/gh-aw (repository)](https://github.com/github/gh-aw)
