Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
298 changes: 298 additions & 0 deletions .github/aw/reuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
---
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot optimize this file for agentic information density, unslop

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 7e55bed — rewrote the file for agentic information density: collapsed the merged-fields table into one compact table, removed wordy intro/explanation prose before each pattern, stripped the separate "Minimal shared component" / "Mixed frontmatter" examples into the pattern code blocks, and tightened all section headers. File went from 464 → 298 lines while retaining all technical content.

description: Imports, shared components, import-schema, and gh aw add/update for GitHub Agentic Workflows
---

# Imports & Reusability

Shared components eliminate duplication of tool configs, prompt instructions, MCP servers, and safe-output jobs across multiple workflows. Each consumer gets updates automatically when the shared file changes.
Comment on lines +5 to +7
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description says .github/agents/agentic-workflows.agent.md was updated to route to an “Imports & Reusability Patterns” prompt, but that change doesn’t appear in this PR’s current file changes. Either include the dispatcher update, or adjust the PR description to match what’s actually being shipped.

Copilot uses AI. Check for mistakes.

---

## Merged Fields

Only these frontmatter fields are merged when a file is imported:

| Field | Merge behaviour |
|---|---|
| `tools:`, `mcp-servers:`, `safe-outputs:`, `network:`, `permissions:`, `runtimes:`, `services:`, `cache:`, `features:` | Deep-merged |
| `env:` | Merged; duplicate keys → compile error |
| `github-app:`, `on.github-app:` | First-wins across imports |
| `steps:`, `pre-steps:`, `pre-agent-steps:`, `post-steps:` | Appended in import order |
| Markdown body | Appended as prompt instructions |

All other fields (`on:`, `engine:`, `timeout-minutes:`, …) are ignored in imported files.
Comment on lines +21 to +23
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “All other fields … are ignored in imported files” line is inaccurate/incomplete: imported files can also merge checkout: (appended; main workflow takes precedence) per the main docs. Please add checkout: to the merged-fields list and avoid implying it’s ignored for imports.

Suggested change
| Markdown body | Appended as prompt instructions |
All other fields (`on:`, `engine:`, `timeout-minutes:`, …) are ignored in imported files.
| `checkout:` | Appended; main workflow takes precedence |
| Markdown body | Appended as prompt instructions |
Other non-merged fields such as `on:`, `engine:`, and `timeout-minutes:` are ignored in imported files.

Copilot uses AI. Check for mistakes.

---

## `imports:` Field

```yaml
# String form
imports:
- shared/reporting.md
- shared/mcp/tavily.md
- copilot-setup-steps.yml # merges copilot-setup-steps job steps

# Object form — pass values to import-schema:
imports:
- uses: shared/repo-memory-standard.md
with:
branch-name: "memory/issue-triage"
description: "Issue triage historical data"
- path: shared/tool-setup.md
with:
environment: staging
env:
MY_OVERRIDE: "value" # env vars for the import's context
checkout: main # ref to check out for this import
```

`with:` values are accessed inside the shared file as `${{ github.aw.import-inputs.<name> }}`.

---

## `import-schema:` Field

Declare typed parameters consumers must (or may) supply:

```yaml
---
import-schema:
branch-name:
type: string
required: true
description: "Branch name for storage (e.g. memory/my-workflow)"
max-items:
type: number
default: 50
description: "Maximum items to retain"
environment:
type: choice
options: [dev, staging, prod]
required: true

tools:
repo-memory:
branch-name: ${{ github.aw.import-inputs.branch-name }}
---
```

### Input types

| Type | Notes |
|---|---|
| `string` | Free-form text |
| `number` | Integer or float |
| `boolean` | `true` / `false` |
| `choice` | Enumerated; must supply `options:` |
| `array` | List of values |
| `object` | Sub-fields via `${{ github.aw.import-inputs.<name>.<subkey> }}` |
Comment on lines +85 to +89
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This “Input types” table looks incomplete vs existing shared components and the compiler: import-schema supports object with optional properties: (one-level deep) and the repo already uses type: integer (e.g. .github/workflows/shared/repo-memory-standard.md). Please document integer (or recommend number and call out integer as accepted) and mention properties: for object schemas.

Suggested change
| `number` | Integer or float |
| `boolean` | `true` / `false` |
| `choice` | Enumerated; must supply `options:` |
| `array` | List of values |
| `object` | Sub-fields via `${{ github.aw.import-inputs.<name>.<subkey> }}` |
| `number` | Numeric value; use for integer or float inputs |
| `integer` | Accepted for whole-number inputs |
| `boolean` | `true` / `false` |
| `choice` | Enumerated; must supply `options:` |
| `array` | List of values |
| `object` | Supports optional `properties:` schema definitions (one level deep); sub-fields are accessed via `${{ github.aw.import-inputs.<name>.<subkey> }}` |

Copilot uses AI. Check for mistakes.

---

## Refactoring Patterns

### 1 — Extract shared MCP server / tool config

Create `.github/workflows/shared/mcp/tavily.md`:

```markdown
---
mcp-servers:
tavily:
url: "https://mcp.tavily.com/mcp/"
env:
TAVILY_API_KEY: "${{ secrets.TAVILY_API_KEY }}"
allowed: [search, extract]
---
```

Each workflow imports it with one line:

```yaml
imports:
- shared/mcp/tavily.md
```

### 2 — Extract shared prompt instructions

```markdown
<!-- shared/keep-it-short.md -->
---
---

Keep all output concise. Use bullet points, not paragraphs.
Never repeat information already visible in the GitHub UI.
```

### 3 — Parameterise with `import-schema:`

```markdown
<!-- shared/jira-mcp.md -->
---
import-schema:
project-key:
type: string
required: true
description: "Jira project key (e.g. ENG, INFRA)"

mcp-servers:
jira:
container: "mcp/jira"
version: "latest"
Comment on lines +141 to +142
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this MCP server example, version: is not a supported mcp-servers.* key (container image tags should be part of the container: string, e.g. mcp/jira:latest). As written, this snippet won’t do what the guide implies for users who copy/paste it.

Suggested change
container: "mcp/jira"
version: "latest"
container: "mcp/jira:latest"

Copilot uses AI. Check for mistakes.
env:
JIRA_TOKEN: "${{ secrets.JIRA_TOKEN }}"
JIRA_PROJECT: ${{ github.aw.import-inputs.project-key }}
allowed: [search_issues, get_issue, list_sprints]
---
```

```yaml
imports:
- uses: shared/jira-mcp.md
with:
project-key: "ENG"
```

### 4 — Compose multiple imports

```yaml
---
on:
schedule: weekly on monday
imports:
- shared/mcp/tavily.md
- shared/gh.md
- shared/reporting.md
- uses: shared/repo-memory-standard.md
with:
branch-name: "memory/weekly-research"
description: "Weekly research snapshots"
---

Conduct weekly research on ${{ github.repository }} dependencies...
```

### 5 — Shared safe-output job

```markdown
<!-- shared/slack-notify.md -->
---
import-schema:
channel:
type: string
required: true

safe-outputs:
jobs:
send-slack-notification:
description: "Post a message to Slack"
runs-on: ubuntu-latest
output: "Slack notification sent"
inputs:
message:
description: "Message text"
required: true
type: string
permissions:
contents: read
steps:
- name: Post to Slack
uses: actions/github-script@v7
env:
SLACK_TOKEN: "${{ secrets.SLACK_TOKEN }}"
CHANNEL: ${{ github.aw.import-inputs.channel }}
with:
script: |
// post message to channel
---
```

```yaml
imports:
- uses: shared/slack-notify.md
with:
channel: "#engineering-alerts"
```

---

## External Imports

### `gh aw add` — Install a remote shared component

```bash
gh aw add https://github.com/org/agentics/blob/main/workflows/shared/reporting.md
```

Downloaded files are stored under `.github/aw/imports/org/agentics/<sha>/`. Reference them in `imports:` by that local path. The `source:` field in the file tracks the origin for future updates.

MCP equivalent: `Use the add tool with url: "<url>"`

### `gh aw update` — Refresh all external imports

```bash
gh aw update
```

Re-fetches every file under `.github/aw/imports/` using its `source:` field. Follows `redirect:` and rewrites `source:` automatically.

MCP equivalent: `Use the update tool`

### Fields for publishable shared components

```yaml
---
source: "org/agentics/workflows/shared/my-component.md@main"
redirect: "org/agentics/workflows/shared/my-component-v2.md@main"
resources:
- shared/mcp/dependency.md # fetched alongside this file
private: false # true → prevent gh aw add from sharing
import-schema:
# ...
---
```

---

## Recommended Directory Layout

```
.github/
└── workflows/
├── my-workflow.md
├── my-workflow.lock.yml # auto-generated
└── shared/
├── mcp/
│ ├── tavily.md
│ ├── notion.md
│ └── github-mcp-app.md
├── reporting.md
├── gh.md
├── keep-it-short.md
└── repo-memory-standard.md
.github/aw/
└── imports/ # installed via gh aw add
└── org/repo/<sha>/
└── workflows_shared_component.md
```

---

## Compile-Time Behaviour

- Imports are resolved at **compile time**; the `.lock.yml` loads shared `.md` bodies at **runtime** — edits to shared files take effect on the next run without recompilation.
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compile-time section currently implies that changes to imported shared files take effect without recompilation, but that’s only true for the imported Markdown body when using runtime imports. Changes to an imported file’s frontmatter (tools, safe-outputs, mcp-servers, etc.) require recompiling the consumer workflow so the merged config in the .lock.yml is updated.

Suggested change
- Imports are resolved at **compile time**; the `.lock.yml` loads shared `.md` bodies at **runtime**edits to shared files take effect on the next run without recompilation.
- Imports are resolved at **compile time**; however, for non-inlined imports the `.lock.yml` loads imported shared `.md` **bodies** at **runtime**. As a result, edits to the imported Markdown body take effect on the next run without recompilation.
- Changes to an imported file’s **frontmatter** (for example `tools:`, `mcp-servers:`, `safe-outputs:`, `env:`, `permissions:`, or other merged fields) **do** require recompilation so the merged config in the consumer’s `.lock.yml` is updated.

Copilot uses AI. Check for mistakes.
- **`inlined-imports: true`** — bundles all imported content at compile time (required for workflows used as repository ruleset status checks). Cannot be combined with `.github/agents/` file imports.
- Any change to the `imports:` list in frontmatter requires recompilation: `gh aw compile <workflow-name>`.
- Editing only the *body* of a shared `.md` file (not its frontmatter) does **not** require recompilation.

---

## Quick Checklist: Extracting a Shared Component

1. Identify the repeated frontmatter block or prompt section
2. Create `.github/workflows/shared/<name>.md` with the extracted content
3. Add `import-schema:` if values differ per consuming workflow
4. Replace the duplicated block in each workflow with an `imports:` entry
5. Recompile: `gh aw compile` (or `gh aw compile <name>`)
6. Verify: `gh aw compile --strict`
Loading