Connector Specification
Connector Specification
Section titled “Connector Specification”Version: 1.0.0
Status: Experimental Working Draft
Publication Date: 2026-11-08
Editor: GitHub Agentic Workflows Team
1. Scope and conformance
Section titled “1. Scope and conformance”This specification defines the declaration-only connector interface implemented by the gh-aw compiler and shared Go/Node runtimes. It covers imported provider definitions, explicitly selected reads, safe outputs, and protected event subscriptions. It does not define a provider catalog, token acquisition service, webhook receiver deployment, or arbitrary API/script execution interface.
The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are normative when capitalized. A conforming declaration satisfies both the workflow JSON Schema and semantic connector validation. A conforming compiler freezes the selected contract without resolving credential values. A conforming execution host enforces phase, resource, endpoint, input, and response constraints.
The connector reference describes the supplied provider examples and their limitations. The connector creation skill provides an authoring procedure. Those examples are not live-readiness certifications.
2. Public authoring and imports
Section titled “2. Public authoring and imports”A connector is an ordinary Markdown file with YAML frontmatter, conventionally
.github/workflows/connectors/<id>.md. Its declaration is under
connectors.<id>. Connector IDs and capability names MUST match
^[a-z][a-z0-9-]{0,62}$. A connector MUST declare at least one capability.
Consumers use normal imports entries with uses and optional typed with
bindings. Local imports follow the compiler’s .github/ confinement rules.
Remote imports use owner/repo/path@ref; deployments SHOULD pin a reviewed
commit. Imported declarations MUST NOT be silently replaced by built-in
definitions, remote fallbacks, or a provider inferred from its name.
Duplicate definitions and generated tool/configuration name collisions MUST
fail rather than overwrite another capability.
import-schema is the ordinary workflow import-binding schema, not the
operation argument schema. It MAY provide resource arrays, reviewed endpoint
settings, secret names, and typed defaults. Binding values MUST NOT contain
credential values. Empty resource collections do not grant access; a selected
capability that needs them MUST fail until it has a valid exact grant.
Constraints on runtime arguments belong in the operation’s inputs even when
the same value is an import input.
2.1 Declaration fields
Section titled “2.1 Declaration fields”Field under connectors.<id> | Contract |
|---|---|
experimental | Boolean; defaults to false. Selecting an experimental connector emits a stability warning, not permission to weaken controls. |
docs | Optional array of unique literal HTTPS documentation URLs without credentials or expressions. Provenance only; MUST NOT be fetched automatically or grant network access. |
endpoints | Nonempty map of named HTTPS origins without credentials, query, fragment, or a non-root path. |
credentials | Named authentication contracts and references, described in section 4. |
resources | Named arrays of exact approved string IDs or other explicitly constrained identifiers. No wildcard authority. |
tools | Named REST/fixed-GraphQL reader operations, each with an exact exposed tool name. |
mcp-servers | Named streamable-HTTP registrations with exact native tool contracts. |
safe-outputs | Named typed mutation operations executed only by a separately authorized safe-output host. |
triggers | Named native-event evidence and normalization contracts, described in section 8. |
Unknown declaration fields MUST fail. There is no public connector context
configuration. Content is obtained through selected readers; the compiler MUST
NOT hydrate event references or run automatic context fetches.
For authoring consistency, declarations SHOULD order fields as experimental,
docs, endpoints, credentials, resources, triggers, tools,
mcp-servers, and safe-outputs. Primitive inputs SHOULD put type and
required before bounds, enum, pattern, and sanitize. Import bindings
SHOULD include concise descriptions and explicit array item types. These are
source-format conventions, not semantic map-order requirements. Authors MAY
reuse provider-local anchors for identical primitive schemas but MUST preserve
scalar quoting, alias dependencies, array order, and independent resource,
credential, and response-evidence contracts.
Merge keys SHOULD precede explicit overrides for compiler compatibility.
Additional nesting in already-aliased containers requires actual Go/Node
conformance evidence, not only a structural YAML parse.
2.2 Internal versioned documents
Section titled “2.2 Internal versioned documents”The compiler lowers a declaration into frozen internal documents with
apiVersion: github.com/gh-aw/connectors/v1: ConnectorSpec,
ConnectorConnection, and ConnectorBinding. Public tools, mcp-servers,
and safe-outputs map to internal mcp, httpMcp, and safeOutputs.
The internal spec ID is aw.github.com/<id>. These documents and prototype
compatibility fixtures are implementation artifacts, not additional files a
third-party author MUST maintain. Internal context fields do not create a
public authoring surface.
3. Explicit selection and phase pruning
Section titled “3. Explicit selection and phase pruning”Importing a declaration selects nothing. The consumer independently selects:
| Consumer surface | Selection |
|---|---|
tools.<id>: [read-name] | Declared REST/GraphQL readers or complete named HTTP MCP registrations. |
tools.<id>: {registration: [nativeTool]} | A nonempty exact subset of an imported HTTP MCP registration. Unknown, duplicate, wildcard, and empty subsets MUST fail. |
safe-outputs.<id>-<operation> | One effect, with null, {}, or the options in section 7. |
on.gateway-dispatch.<id>: [trigger] | A protected connector event subscription. Qualified root <id>-<trigger> selections lower to the same gateway route. |
REST read-tool names come from tool; HTTP MCP names are derived from the
registration and native method. Effect selectors use hyphens; generated effect
MCP tool names use underscores, for example example_add_note. Authors MUST
inspect generated schemas rather than invent a tool prefix.
New local REST/GraphQL reader tool names SHOULD use unprefixed snake_case.
Existing hyphenated and provider-prefixed reader names remain supported; a
selector MUST NOT be silently converted into a callable reader name. Hosted
HTTP MCP methods MUST retain their exact native names and case.
The compiler MUST remove unselected capabilities and unused endpoints, grants, and credential references from each delivered phase plan. Writer credentials MUST NOT reach the agent. Removing all selections MUST remove connector execution from the workflow. A selected endpoint MUST also be approved by the workflow/host network policy; importing an endpoint is not network approval.
4. Authentication and authority
Section titled “4. Authentication and authority”A credential declares phase, header, scheme, nonempty scopes, and one
source route. Public execution uses agent or safe-output phases. Scope
strings document provider requirements; they MUST NOT be treated as permission
grants. The runtime MUST use only the selected phase’s host-owned resolver.
| Field or route | Requirements |
|---|---|
header | Authorization, X-API-Key, or PRIVATE-TOKEN. |
scheme | bearer, token, basic, or raw. Prefixes are respectively Bearer , token , Basic , and empty. A Basic secret contains the prepared encoding, not a request to perform login. |
token: {secret: NAME} | A stored secret-name reference. secret: NAME is the legacy shorthand. Names MUST be valid and MUST NOT impersonate reserved minted-token references. |
github-app | Explicit client ID/private-key reference, installation scope, and bounded permissions. An explicit owner requires exact repositories. Agent-phase permissions MUST NOT include write; missing credentials MUST NOT be ignored. |
github-oidc: {audience: ...} | A nonempty bounded literal audience; requires Authorization/bearer and phase-specific GitHub OIDC plumbing. |
Exactly one source route MUST be used for an executable credential. GitHub App tokens are GitHub installation tokens; GitHub OIDC produces an identity JWT. Neither route implements a provider-token exchange. Provider consent, installation, token renewal, audience acceptance, and ACLs remain external.
Resource-constrained arguments MUST be required strings and match an exact authored grant before credential resolution. Numeric response IDs MAY use the canonical identity correlation in section 6; argument values MUST NOT be silently coerced, trimmed, or granted by that comparison. Independent grant lists do not prove tenant, parent, or tuple membership. IDs returned by a read MUST NOT become write authority automatically.
Hosts MUST reject redirects and endpoint changes before forwarding credentials, and MUST NOT switch credentials after an authorization denial. Token values MUST NOT appear in source, prompts, plans, logs, or published artifacts.
5. Typed operations and fixed requests
Section titled “5. Typed operations and fixed requests”REST/GraphQL readers and safe outputs share an operation shape:
credential, optional inputs/resources, required request and
maxResponseBytes, and optional response/policy fields. Read operations also
require tool, an exact name matching ^[A-Za-z][A-Za-z0-9_.-]{0,127}$.
5.1 Inputs
Section titled “5.1 Inputs”| Input field | Requirements |
|---|---|
type | string, integer, number, or boolean; no arbitrary object, array, expression, or runtime default. |
required | Boolean. Unknown arguments and missing required values MUST fail. |
maxLength, minLength | String code-point bounds. maxLength is required for strings, from 1 to 65536; minLength is between zero and maxLength. |
enum | Exact allowed string values; distinct from resource grants. |
pattern | A valid bounded string regex, at most 1024 bytes. Authors SHOULD use syntax compatible with both Go and Node. |
minimum, maximum | Numeric bounds for number/integer inputs; minimum MUST NOT exceed maximum. |
sanitize | title, body (Markdown), body-plain (plain text), or body-plain-compact (plain text with single ASCII spaces/newlines), only for human text. Sanitized titles require at least 20 code points; body inputs that must contain actor text SHOULD set minLength: 1. |
Sanitizers and protected generated attribution run in the trusted publication path before staging or delivery. Body limits include generated content. Resource IDs, status values, labels, and destinations MUST NOT be annotated as body text. The low-level raw transport APIs do not replace publication formatting.
5.2 Requests and values
Section titled “5.2 Requests and values”request.endpoint references a declared origin. method is GET, POST, PUT,
PATCH, or DELETE. path MUST be a fixed absolute path without query, fragment,
traversal, embedded expressions, or arbitrary escaping.
pathInputs maps fixed {placeholder} names to required string arguments;
each substituted value MUST be a single safe segment.
query and body map fields to typed values, not textual interpolation:
| Value form | Meaning |
|---|---|
{input: name} | Data from a declared input. |
{literal: value} | Fixed authored non-null JSON data. |
{object: {...}} | A recursively declared object of values. |
{array: [...]} | A recursively declared array of values. |
A value MUST choose exactly one form. Input values MAY use the supported
jira-adf or confluence-storage encodings or a bounded authored prefix;
these are serializers, not code execution. request.headers holds fixed
reviewed metadata and MUST NOT replace authentication routing.
Readers MUST use GET or POST with a fixed GraphQL document beginning with
query . Read documents MUST NOT contain mutation/subscription tokens.
GraphQL variables use request.query; GraphQL MUST NOT coexist with body.
GET MUST NOT carry a body or patch. Arbitrary agent-provided queries, URLs,
scripts, and JSON patches are unsupported.
request.patch and additionalPatch permit only authored fixed-path
add/replace/test JSON Patch entries on safe-output POST/PATCH.
additionalPatch is bounded to 32 entries and MUST NOT override an existing
patch path. It is not an agent patch escape hatch.
5.3 Hosted HTTP MCP
Section titled “5.3 Hosted HTTP MCP”Each mcp-servers registration requires a fixed HTTPS url, an agent credential,
readOnly: true, a nonempty exact tools map, and maxResponseBytes.
Each native tool declares the same primitive inputs and exact resources
constraints. Optional fixed registration headers use X-MCP-* names.
Endpoint comparison uses the canonical URL representation, including the root
slash and default HTTPS port; redirects and different endpoint paths remain
prohibited. An omitted MCP arguments object is an empty object, not permission
to omit required inputs. Explicit null and other non-object arguments MUST fail.
The shared local adapter MUST validate tool selection, arguments, grants, phase,
and endpoint before forwarding tools/call. Remote read-only annotations are
advisory, not proof of provider authorization. Initialization success does not
prove a later tool is authorized. REST retry configuration does not apply to
the MCP protocol. Interactive input-required results are not completed reads.
6. Response evidence and bounds
Section titled “6. Response evidence and bounds”maxResponseBytes MUST be from 1 to 1048576. Malformed JSON, GraphQL errors,
missing required evidence, and failed declared checks MUST fail explicitly.
Responses and MCP content remain untrusted data even after validation.
Use body-plain when an API consumes literal text, including Jira ADF text nodes.
Use body-plain-compact for APIs such as Zendesk that collapse repeated ASCII
spaces and newlines; it prepares that canonical text before staging or sending.
The trusted publisher applies the same sanitization,
redaction, code-point limits, and protected attribution as Markdown publication,
but serializes text without Markdown entity escaping or HTML comment markers.
Provenance is retained as a plain gh-aw-agentic-workflow metadata line, even
when the visible footer is disabled. Response identity, privacy, and exact
body-evidence checks remain in force; provider normalization can still cause an
uncertain write outcome and MUST NOT trigger an automatic retry.
| Response field | Required check |
|---|---|
responseChecks | JSON Pointer to exact authored expected JSON value. |
responseRequired | Required JSON Pointers. |
responseTypes | Pointer to primitive string/number/integer/boolean type. |
responseInputs | Pointer to exact required request input; no coercion. |
responseResourceInputs | Pointer to required resource-constrained string input; canonical string/integer response identity MUST equal that requested ID. |
responseResources | Pointer to exact granted resource collection. |
responseOptionalEmpty | Explicit pointers where empty optional evidence is permitted; other identity checks still apply. |
responseContains | Array membership evidence linking a required input to a returned relationship. |
responseLimits | Named response-array size bounds from 1 to 100; "" names a root array. |
responseAnyInputs | Input matching one of one to four reviewed identity pointers. |
responseWhen | Bounded data-only predicate over returned evidence, never an authority grant. |
project | Named JSON Pointer fields exposed after all checks. Omission returns the validated response, not an automatic minimal projection. |
Authors SHOULD project only the evidence their consumer needs and distinguish metadata from bodies, diffs, discussions, or delivery receipts. Bounded collection checks support one array wildcard in the designated response bindings; every returned item MUST satisfy the check. Empty collections are valid when the contract permits them, not discovered authority. Pagination and cursor traversal MUST NOT be automatic; a declaration needing complete evidence MUST explicitly reject incomplete pages.
The encoded selected plan MUST NOT exceed 65536 bytes. Oversized plans MUST fail with a request to select fewer capabilities, not silently omit controls. Declaration/development documents have a separate 256 KiB limit. Response bytes, argument documents, and string code points are different bounds.
7. Safe-output execution
Section titled “7. Safe-output execution”Safe outputs MUST execute outside the agent credential boundary and require explicit host write authorization. The trusted host MUST revalidate inputs, grants, and the selected frozen operation. Connector writes are non-reviewable outputs under the normal threat-detection gate; warning or required failed/missing detection conclusions MUST NOT be overridden by agent-supplied policy fields.
7.1 Workflow-owned options
Section titled “7.1 Workflow-owned options”Option on safe-outputs.<id>-<operation> | Meaning |
|---|---|
max | Integer 1 through 100; default 1. Counts attempted operation calls, including failures, before executing the handler. |
staged | Boolean or Actions expression. Global/compiler-forced staging wins over per-operation false. |
samples | One argument object or an array of objects validated against the generated tool schema. Requires features.samples: true or compile --use-samples for replay. |
Staging MUST suppress mutations, writer credential resolution/minting, preflights,
policy checks, and creation receipts. It does not suppress selected readers or
arbitrary workflow scripts. A staged alias MAY remain in unresolvedInputs;
this is not verified identity or delivery.
Samples use the ordinary submission path and retain budgets and validation. Replay MUST NOT interpret interpolated strings as control JSON or grants. Samples alone do not enable staging and MUST NOT be described as a dry run.
7.2 Narrowing policies, receipts, and binary inputs
Section titled “7.2 Narrowing policies, receipts, and binary inputs”trustedInputs binds reviewed host values or secret-name references rather than
agent-chosen destinations. preflight is a fixed same-phase read using those
inputs. checks allows at most four fixed same-credential reads of canonical
operation arguments before a write. All policy reads narrow existing authority;
they MUST NOT grant a new destination.
lookups allows at most four ordered fixed reads with independent exact alias
and canonical-ID grants. Cycles and duplicate targets MUST fail. Canonical calls
skip unnecessary resolution. Lookup chains MUST validate their grants before
credentials, and MUST NOT mix with trusted-input or creation-receipt bindings.
creates, createdResources, and validated execution-local receipts permit
declared follow-ups. Receipt identities and scope MUST be verified against the
authenticated creation response. A proposal’s temporary alias, an agent-supplied
ID, an opaque safe-output output_id, and a staged creation are not resource
receipts. Receipt checks do not by themselves prove comment or note persistence.
request.binary binds a staged regular-file snapshot with input, maxBytes,
optional extensions, and rejectContains policy. The host MUST recheck its
root, content digest, suffix, and byte limits before credentials. Node guarded
file execution requires Linux. File transfer MUST NOT follow arbitrary
provider-returned URLs or accept inline JSON/base64 as a substitute for the
staged-file channel.
7.3 Retries
Section titled “7.3 Retries”No REST retry policy means one request attempt. retry declares
maxAttempts (1 through 4, including the first request), backoffMs
(1 through 1000), exact transient retryOn statuses, and optional idempotent.
Backoff doubles and respects Retry-After within the total 20-second operation
deadline. Authorization, redirects, response-evidence failures, and uncertain
transport failures MUST NOT retry.
Write retries additionally require idempotent: true and a reviewed repeat-safe
PUT/PATCH/DELETE contract. POST creates and appends MUST NOT retry. An HTTP method
alone does not establish idempotency. HTTP retries within a single invocation
do not allocate another workflow max allowance.
8. Triggers and context boundary
Section titled “8. Triggers and context boundary”A trigger declares verificationProfile, nonempty nativeEvents, equality
match, JSON Pointer normalize, and any exact resources/primitive types.
Gateway-selected triggers require fixed reviewed resourceOrigins; they are
distinct from request endpoints. Optional when, filters, and variants
express bounded source-evidence conditions. URL identity/prefix declarations
constrain canonicalization, not native delivery authentication.
Predicates follow the frozen gh-aw/event-predicates/v1 contract. Missing or
ambiguous lifecycle evidence MUST be a nonmatch, not permission to fetch a
resource or infer a transition. Consumer filters narrow declared subscriptions
and MUST NOT widen source grants.
The compiler emits digest-bound subscription data through the existing webhook gateway. Repository opt-in, source grants, App provenance, and version/hash-bound admission remain required. The trusted receiver authenticates original native evidence and evaluates predicates before canonical projection. Compiling a trigger MUST NOT claim receiver enrollment, replay protection deployment, webhook installation, or live operability. Until an approved receiver supports the exact profile and mapping, the subscription is nonactivating. Event references are not hydrated bodies.
9. Minimal declaration and consumer
Section titled “9. Minimal declaration and consumer”The following is a synthetic contract, not a claim about a real provider API.
Its illustrative endpoint MUST NOT be used for live tests. It defines a fixed
read and a note append, exact record grants, minimal response evidence, and
separate credential names. A real provider author replaces the request/response
shapes from official documentation and adds its consulted docs references.
---connectors: example: experimental: true endpoints: api: https://api.example.com credentials: reader: phase: agent header: Authorization scheme: bearer scopes: [records:read] token: secret: ${{ github.aw.import-inputs.reader-secret }} writer: phase: safe-output header: Authorization scheme: bearer scopes: [notes:write] token: secret: ${{ github.aw.import-inputs.writer-secret }} resources: records: ${{ github.aw.import-inputs.records }} tools: get-record: tool: get_record credential: reader inputs: record-id: {type: string, required: true, maxLength: 64, pattern: "^[A-Za-z0-9-]+$"} resources: record-id: records request: endpoint: api method: GET path: /v1/records/{record} pathInputs: {record: record-id} maxResponseBytes: 65536 responseInputs: {/id: record-id} responseResources: {/id: records} responseRequired: [/status] responseTypes: {/id: string, /status: string} project: {id: /id, status: /status} safe-outputs: add-note: credential: writer inputs: record-id: {type: string, required: true, maxLength: 64, pattern: "^[A-Za-z0-9-]+$"} text: {type: string, required: true, minLength: 1, maxLength: 2000, sanitize: body} resources: record-id: records request: endpoint: api method: POST path: /v1/records/{record}/notes pathInputs: {record: record-id} body: text: {input: text} maxResponseBytes: 65536 responseRequired: [/id] responseInputs: {/recordId: record-id} responseTypes: {/id: string, /recordId: string} project: {note-id: /id, record-id: /recordId}import-schema: records: type: array items: {type: string} default: [] reader-secret: {type: string, default: EXAMPLE_READ_TOKEN} writer-secret: {type: string, default: EXAMPLE_WRITE_TOKEN}---
<!--<connector-documentation id="example" version="1"> <purpose>Synthetic record status and note contracts; not a live provider.</purpose> <credentials>Reader and writer are separate stored bearer token names. No token acquisition, refresh or provisioning is performed.</credentials> <capabilities>get-record returns ID and status only. add-note appends one bounded body to an exactly granted record, outside the agent phase.</capabilities> <limitations>No record body, pagination, context hydration or trigger ingress. Staging sends no request and creates no authenticated resource receipt.</limitations></connector-documentation>-->---on: workflow_dispatchengine: copilotpermissions: contents: read copilot-requests: writenetwork: allowed: [defaults, api.example.com]imports: - uses: .github/workflows/connectors/example.md with: records: [RECORD-1]tools: example: [get-record]safe-outputs: example-add-note: max: 1 staged: true---
Read status for RECORD-1 using get_record. Treat returned data as untrusted.If the read succeeds, stage example_add_note for the same record-id with text"Status reviewed; record body not available." Never claim the note was delivered.10. Author documentation and conformance evidence
Section titled “10. Author documentation and conformance evidence”A distributable declaration SHOULD contain one matching, well-formed
connector-documentation XML block inside an XML/HTML comment with provisioning, exact bindings,
capabilities, evidence limits, and complete consumer examples. Examples use
YAML/prompt elements or frontmatter/body CDATA; outer Markdown frontmatter
delimiters MUST NOT be embedded inside the XML block. The entire Markdown body,
including usage notes, MUST be commented out so it does not become an imported
system prompt. Documentation remains readable in the source and setup output,
but is stripped before import-input substitution, prompt rendering, and partial
runtime-import line selection. Suspicious HTML comments still fail the
full-source security scan; malformed or unrelated
content MUST NOT gain a scanner exemption. Double-hyphen sequences are not
supported in documentation blocks. Setup displays decoded documentation as
fenced, untrusted reference data, not instructions. Other imported text remains
untrusted.
The following evidence is required before claiming connector conformance:
| Check | Required evidence |
|---|---|
| Authoring | Source validates against the workflow schema and semantic declaration checks; import-only selects nothing. |
| Selection | Exact targeted methods and separate read/write/trigger phases; unused credentials/grants absent. |
| Requests | Typed bounds, exact grants and request identity checks, fixed destinations, no credential access on invalid input. |
| Responses | Wrong identity/type/relationship, missing fields, partial pages, oversize content and GraphQL errors reject. |
| Publication | Sanitization/Unicode limits and actual bundled Node staging agree with Go revalidation; staged calls resolve no writer secret and make no HTTP request. |
| Failure policy | Budgets, declared retries, threat gating and receipt scope remain enforced on failure. |
| Distribution | Local and pinned imports compile; complete consumer/XML examples compile; deployed runtime includes transitive dependencies. |
| Trigger, if declared | Offline native fixtures establish matching/nonmatching evidence and Go/Node predicate parity; result states operational: false. |
gh aw connector <id> setup is offline metadata discovery by default.
An explicit --repo OWNER/REPO permits read-only repository secret/variable
name inventory for the declared phase requirements. Missing settings produce
provisioning commands, not credential collection or writes. Inventory failures
MUST remain errors with unknown status, not fabricated missing/present results.
Name presence MUST NOT be reported as proof of provider access, App installation,
OIDC trust, or availability of organization/environment settings.
gh aw connector <id> test --phase safe-output always stages; annotated text
requires a trusted matching --node-runtime.
--phase trigger projects fixture JSON offline.
In contrast, --phase agent contacts the provider with named environment
credentials and is a live test, not an offline validation command.
Compilation, mocks, setup output, and staging MUST be reported separately from provider authorization, ingress readiness, live delivery, and operational value. Live tests require separately authorized scope and the debugging execution gates.
11. Implementation references
Section titled “11. Implementation references”The public shape is ConnectorDeclaration in
connector_declaration.go.
The workflow schema
and semantic validators in
pkg/connectors
jointly define accepted values. Selection/lowering is implemented by
connectors.go, connector_mcp_selection.go, and compiler_connectors.go.
The shared publication runtime is
connector_runtime.cjs.
Structural internal schemas alone MUST NOT be treated as executable authority.