Imports
Syntax
Section titled “Syntax”Use imports: in frontmatter or {{#import ...}} in markdown to share workflow components across multiple workflows.
---on: issuesengine: copilotimports: - shared/common-tools.md - shared/mcp/tavily.md---
# Your Workflow
Workflow instructions here...Parameterized imports (uses/with)
Section titled “Parameterized imports (uses/with)”Shared workflows that declare an import-schema accept runtime parameters. Use the uses/with form to pass values:
---on: issuesengine: copilotimports: - uses: shared/mcp/serena.md with: languages: ["go", "typescript"]---uses is an alias for path; with is an alias for inputs.
Single-import constraint
Section titled “Single-import constraint”A workflow file can appear at most once in an import graph. If the same file is imported more than once with identical with values it is silently deduplicated. Importing the same file with different with values is a compile-time error:
import conflict: 'shared/mcp/serena.md' is imported more than once with different 'with' values.An imported workflow can only be imported once per workflow. Previous 'with': {"languages":["go"]} New 'with': {"languages":["typescript"]}In markdown, use the special {{#import ...}} directive:
---...---
# Your Workflow
Workflow instructions here...
{{#import shared/common-tools.md}}Shared Workflow Components
Section titled “Shared Workflow Components”Files without an on field are shared workflow components — validated but not compiled into GitHub Actions, only imported by other workflows. The compiler skips them with an informative message.
Import Schema (import-schema)
Section titled “Import Schema (import-schema)”Use import-schema to declare a typed parameter contract. Callers pass values via with; the compiler validates them and substitutes them into the shared file’s frontmatter and body before processing.
---# shared/deploy.md — no 'on:' field, shared component onlyimport-schema: region: type: string required: true environment: type: choice options: [staging, production] required: true count: type: number default: 10 languages: type: array items: type: string required: true config: type: object description: Configuration object properties: apiKey: type: string required: true timeout: type: number default: 30
mcp-servers: my-server: url: "https://example.com/mcp" allowed: ["*"]---
Deploy ${{ github.aw.import-inputs.count }} items to ${{ github.aw.import-inputs.region }}.API key: ${{ github.aw.import-inputs.config.apiKey }}.Languages: ${{ github.aw.import-inputs.languages }}.Supported types
Section titled “Supported types”| Type | Description | Extra fields |
|---|---|---|
string | Plain text value | — |
number | Numeric value | — |
boolean | true/false | — |
choice | One of a fixed set of strings | options: [...] |
array | Ordered list of values | items.type (element type) |
object | Key/value map | properties (one level deep) |
Each field supports required: true and an optional default value.
Accessing inputs in shared workflows
Section titled “Accessing inputs in shared workflows”Use ${{ github.aw.import-inputs.<key> }} to substitute a top-level value; use dotted notation for object sub-fields (e.g. ${{ github.aw.import-inputs.config.apiKey }}). Substitution applies to both frontmatter and body, so inputs can drive any field such as mcp-servers or runtimes.
Calling a parameterized shared workflow
Section titled “Calling a parameterized shared workflow”---on: issuesengine: copilotimports: - uses: shared/deploy.md with: region: us-east-1 environment: staging count: 5 languages: ["go", "typescript"] config: apiKey: my-secret-key timeout: 60---The compiler validates required fields, choice options, array element types, and object properties. Unknown keys are compile-time errors.
Path Resolution
Section titled “Path Resolution”Import paths are resolved using one of three modes depending on their format.
Relative paths (default)
Section titled “Relative paths (default)”Paths that do not start with .github/, /, or an owner/repo/ prefix are resolved relative to the importing workflow’s directory. When compiling with the default --dir value, that directory is .github/workflows/.
---on: issuesengine: copilotimports: - shared/common-tools.md # → .github/workflows/shared/common-tools.md - ../agents/helper.md # → .github/agents/helper.md (.. goes up from .github/workflows/)---Repo-root-relative paths
Section titled “Repo-root-relative paths”Paths starting with .github/ or / are resolved from the repository root. Absolute paths (/) must point inside .github/ or .agents/; any other prefix is rejected at compile time for security.
---on: pull_requestengine: copilotimports: - .github/agents/code-reviewer.md # resolved from repo root - .github/workflows/shared/app.md # resolved from repo root---This form is required when workflows in different directories need to import the same shared file using a stable path, and is the supported way to import files from the .github/agents/ directory.
Cross-repo imports
Section titled “Cross-repo imports”Paths matching the owner/repo/path@ref format are fetched from GitHub at compile time and cached locally. The @ref suffix pins the import to a tag, branch, or commit SHA.
---on: issuesengine: copilotimports: - acme-org/shared-workflows/shared/reporting.md@v2.1.0 # pinned to a tag - acme-org/shared-workflows/shared/tools.md@main # track a branch - acme-org/shared-workflows/shared/helpers.md@abc1234 # locked to a SHA---Remote imports are cached in .github/aw/imports/ by commit SHA, enabling offline compilation. See Remote Repository Imports for details.
Worked example — all three forms
Section titled “Worked example — all three forms”---on: issuesengine: copilotimports: # 1. Relative path – resolved relative to .github/workflows/ - shared/mcp/tavily.md # 2. Repo-root-relative – resolved from the repository root - .github/agents/my-expert-agent.md # 3. Cross-repo – fetched from GitHub at compile time - acme-org/shared-workflows/shared/reporting.md@v1.0.0---
# My Workflow
Use the imported tools, agent, and reporting configuration.Section references and optional imports
Section titled “Section references and optional imports”Append #SectionName to any path to import a single section from a markdown file:
imports: - shared/tools.md#WebSearchUse the {{#import? ...}} syntax to mark an import as optional, which skips missing files silently instead of failing compilation.
Remote Repository Imports
Section titled “Remote Repository Imports”Import shared components from external repositories using the owner/repo/path@ref format:
---on: issuesengine: copilotimports: - acme-org/shared-workflows/mcp/tavily.md@v1.0.0 - acme-org/shared-workflows/tools/github-setup.md@main---
# Issue Triage Workflow
Analyze incoming issues using imported tools and configurations.Supported refs: semantic tags (@v1.0.0), branches (@main), or commit SHAs. See Reusing Workflows for installation and update workflows.
Import Cache
Section titled “Import Cache”Remote imports are cached in .github/aw/imports/ by commit SHA, enabling offline compilation. The cache is git-tracked with .gitattributes for conflict-free merges. Local imports are never cached.
Agent Files
Section titled “Agent Files”Agent files are markdown documents in .github/agents/ that add specialized instructions to the AI engine. Import them from your repository or from external repositories.
Local Agent Imports
Section titled “Local Agent Imports”Import agent files from your repository’s .github/agents/ directory:
---on: pull_requestengine: copilotimports: - .github/agents/code-reviewer.md---Remote Agent Imports
Section titled “Remote Agent Imports”Import agent files from external repositories using the owner/repo/path@ref format:
---on: pull_requestengine: copilotimports: - githubnext/shared-agents/.github/agents/security-reviewer.md@v1.0.0---
# PR Security Review
Analyze pull requests for security vulnerabilities using the shared security reviewer agent.Remote agent imports support the same @ref versioning syntax as other remote imports.
Constraints
Section titled “Constraints”- One agent per workflow: Only one agent file can be imported per workflow (local or remote)
- Agent path detection: Files in
.github/agents/directories are automatically recognized as agent files - Caching: Remote agents are cached in
.github/aw/imports/by commit SHA, enabling offline compilation
Frontmatter Merging
Section titled “Frontmatter Merging”Allowed Import Fields
Section titled “Allowed Import Fields”Shared workflow files (without on: field) can define:
import-schema:- Parameter schema forwithvalidation and input substitutiontools:- Tool configurations (bash, web-fetch, github, mcp-*, etc.)mcp-servers:- Model Context Protocol server configurationsservices:- Docker services for workflow executionsafe-outputs:- Safe output handlers and configurationmcp-scripts:- MCP Scripts configurationsnetwork:- Network permission specificationspermissions:- GitHub Actions permissions (validated, not merged)runtimes:- Runtime version overrides (node, python, go, etc.)secret-masking:- Secret masking steps
Agent files (.github/agents/*.md) can additionally define:
name- Agent namedescription- Agent description
Other fields in imported files generate warnings and are ignored.
Field-Specific Merge Semantics
Section titled “Field-Specific Merge Semantics”Imports are processed using breadth-first traversal: direct imports first, then nested. Earlier imports in the list take precedence; circular imports fail at compile time.
| Field | Merge strategy |
|---|---|
tools: | Deep merge; allowed arrays concatenate and deduplicate. MCP tool conflicts fail except on allowed arrays. |
mcp-servers: | Imported servers override same-named main servers; first-wins across imports. |
network: | allowed domains union (deduped, sorted). Main mode and firewall take precedence. |
permissions: | Validation only — not merged. Main must declare all imported permissions at sufficient levels (write ≥ read ≥ none). |
safe-outputs: | Each type defined once; main overrides imports. Duplicate types across imports fail. |
runtimes: | Main overrides imports; imported values fill in unspecified fields. |
services: | All services merged; duplicate names fail compilation. |
steps: | Imported steps prepended to main; concatenated in import order. |
jobs: | Not merged — define only in the main workflow. Use safe-outputs.jobs for importable jobs. |
safe-outputs.jobs | Names must be unique; duplicates fail. Order determined by needs: dependencies. |
Example — tools.bash.allowed merging:
# main.md: [write]# import: [read, list]# result: [read, list, write]Importing Steps
Section titled “Importing Steps”Share reusable pre-execution steps — such as token rotation, environment setup, or gate checks — across multiple workflows by defining them in a shared file:
---description: Shared token rotation setupsteps: - name: Rotate GitHub App token id: get-token uses: actions/create-github-app-token@v1 with: app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }}---Any workflow that imports this file gets the rotation step prepended before its own steps:
---on: issuesengine: copilotimports: - shared/rotate-token.mdpermissions: contents: read issues: writesteps: - name: Prepare context run: echo "context ready"---
# My Workflow
Process the issue using the rotated token from the imported step.Steps from imports run before steps defined in the main workflow, in import declaration order.
Importing MCP Servers
Section titled “Importing MCP Servers”Define an MCP server configuration once and import it wherever needed:
---description: Tavily web search MCP servermcp-servers: tavily: url: "https://mcp.tavily.com/mcp/?tavilyApiKey=${{ secrets.TAVILY_API_KEY }}" allowed: ["*"]network: allowed: - mcp.tavily.com---Import it into any workflow that needs web search:
---on: issuesengine: copilotimports: - shared/mcp/tavily.mdpermissions: contents: read issues: write---
# Research Workflow
Search the web for relevant information and summarize findings in the issue.Importing Top-level jobs:
Section titled “Importing Top-level jobs:”Top-level jobs: defined in a shared workflow are merged into the importing workflow’s compiled lock file. The job execution order is determined by needs entries — a shared job can run before or after other jobs in the final workflow:
---description: Shared build job that compiles artifacts for the agent to inspect
jobs: build: runs-on: ubuntu-latest needs: [activation] outputs: artifact_name: ${{ steps.build.outputs.artifact_name }} steps: - uses: actions/checkout@v6 - name: Build id: build run: | npm ci && npm run build echo "artifact_name=build-output" >> "$GITHUB_OUTPUT" - uses: actions/upload-artifact@v4 with: name: build-output path: dist/
steps: - uses: actions/download-artifact@v4 with: name: ${{ needs.build.outputs.artifact_name }} path: /tmp/build-output---Import it so the build job runs before the agent and its artifacts are available as pre-steps:
---on: pull_requestengine: copilotimports: - shared/build.mdpermissions: contents: read pull-requests: write---
# Code Review Workflow
Review the build output in /tmp/build-output and suggest improvements.In the compiled lock file the build job appears alongside activation and agent jobs, ordered according to each job’s needs declarations.
Importing Jobs via safe-outputs.jobs
Section titled “Importing Jobs via safe-outputs.jobs”Jobs defined under safe-outputs: can be shared across workflows. These jobs become callable MCP tools that the AI agent can invoke during execution:
---description: Shared notification jobsafe-outputs: notify-slack: description: "Post a message to Slack" runs-on: ubuntu-latest output: "Notification sent" inputs: message: description: "Message to post" required: true type: string steps: - name: Post to Slack env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} run: | curl -s -X POST "$SLACK_WEBHOOK" \ -H "Content-Type: application/json" \ -d "{\"text\":\"${{ inputs.message }}\"}"---Import and use it in multiple workflows:
---on: issuesengine: copilotimports: - shared/notify.mdpermissions: contents: read issues: write---
# My Workflow
Process the issue. When done, use notify-slack to send a summary notification.Error Handling
Section titled “Error Handling”- Circular imports: Detected at compile time.
- Missing files: Use
{{#import? file.md}}for optional imports; required imports fail if missing. - Conflicts: Duplicate safe-output types across imports fail — define in main workflow to override.
- Permissions: Insufficient permissions fail with detailed error messages.
Remote imports are cached by commit SHA in .github/aw/imports/. Keep import chains shallow and consolidate related imports; every compilation records imports in the lock file manifest.
Using Imports in Repository Rulesets (inlined-imports: true)
Section titled “Using Imports in Repository Rulesets (inlined-imports: true)”When a workflow is configured as a required status check in a repository ruleset, it runs in a restricted context that does not have access to other files in the repository. Shared files imported with the imports: field are loaded at runtime from the repository checkout, but this checkout is not available in the ruleset context, producing an error such as:
ERR_SYSTEM: Runtime import file not found: workflows/shared/file.mdSet inlined-imports: true to bundle all imported content directly into the compiled .lock.yml at compile time, so no file system access is needed at runtime:
---on: pull_requestengine: copilotinlined-imports: trueimports: - shared/common-tools.md - shared/security-setup.md---
# My Workflow
Workflow instructions here.After adding inlined-imports: true, recompile the workflow:
gh aw compile my-workflowRelated Documentation
Section titled “Related Documentation”- Packaging and Updating - Complete guide to managing workflow imports
- Frontmatter - Configuration options reference
- MCPs - Model Context Protocol setup
- Safe Outputs - Safe output configuration details
- Network Configuration - Network permission management