Write your organization's Copilot skills, agents, and MCP servers once. Specialize them per team with typed data. Ship them as GitHub Agent Plugins through one marketplace.
TypeFerence is an experimental authoring and reuse layer for Agent Plugins, with GitHub Copilot as its output adapter. It compiles small .tfer source documents into ordinary plugin directories and a Copilot marketplace index. Copilot and GitHub install, enable, authenticate, and run what it produces; TypeFerence never does.
Read the specification (version 8), the decisions behind it, the output contract, and the Helio example.
Status. Version 8 is implemented: the plugin is the composition and binding root, and agents extend agents (ADR-0006). Copilot's native components (rules, commands, hooks, LSP servers, agent-scoped MCP servers) are emitted and validated against the output contract, but have not yet been installed in Copilot. The rebuilt playground has not yet been exercised by hand.
A good skill lives in one repository. Every other team copies it, and the copies drift. One developer maintaining a README skill across thirty repositories keeps thirty near-identical files in sync by hand. When several teams publish to one internal marketplace, nothing stops two of them shipping different skills called review, or an MCP server that silently replaces a user's own.
TypeFerence makes the shared part source:
- Shared templates. A platform team writes a template once: a skill, a document, or a whole profile with blanks such as
{{team.queue}}. - Typed team data. Each team supplies one small data document of the template's context type. That type is the contract: every instance must fill every required field, and a form can be generated from it.
- Specialization by extension. A team can extend a shared skill instead of copying it, and anyone can embed a team's plugin and change one skill or one line of its agent. Fixes to the shared parts reach every specialization on the next build.
- Checks the plugin format cannot express. A skill always ships with the MCP servers it needs. Every skill, agent, plugin, and server name means one thing across the whole marketplace. A pipeline skill's output schema ships beside it for the runner to validate against.
- Reviewable output. Builds are byte-for-byte reproducible, so a change to a shared template shows up as a diff of exactly what changed for every team.
A package is a manifest plus small documents whose kind comes from the file suffix. Prose is ordinary Markdown; types describe only the values that vary between instances.
A context type is the contract every team instantiates against:
---
displayName: Team
instanceName: id
fields:
id:
type: string
required: true
description: Lowercase and hyphenated; prefixes the team's skill names.
name:
type: string
required: true
queue:
type: string
required: true
tier:
type: string
default: standard
choices:
- standard
- critical
---
A template skill uses its fields, and can require an MCP server:
---
description: Summarize open requests in the {{team.name}} ticket queue.
parameters:
team: context-types/team.contexttype.tfer
requiresServers:
- servers/helio-tickets.server.tfer
---
Summarize open requests in the {{team.queue}} queue for {{team.name}}, and call
out anything that would block a {{team.tier}}-tier release.
A team supplies data, a thin agent, and the plugin that ships them. The plugin is the binding root: it embeds the shared profile and binds the team's data, and everything it ships renders with that data:
---
contextType: helio/core:context-types/team.contexttype.tfer
values:
id: payments
name: Payments
queue: PAY-OPS
tier: critical
---
---
description: Operations agent for the Helio payments team.
---
You support the {{team.name}} team's engineers and release pipelines.
---
description: The Helio payments operations agent, for engineers and release pipelines.
embeds:
- helio/core:profiles/team-ops.profile.tfer
agents:
- agents/payments-ops.agent.tfer
with:
team: data/payments-team.context.tfer
---
The build emits payments-queue-summary, payments-onboard-teammate, and the other skills of the profile, each with the team's values filled in, plus an mcp.json holding exactly the servers those skills need.
Other document kinds:
- Profiles are reusable compositions (skills, documents, agents, native components) that plugins embed.
- Capabilities share input and output schemas across unrelated skills.
- Servers declare MCP servers, shipped in
mcp.jsonwith the skills that need them or scoped to one agent. - Rules, commands, hooks, and LSP servers are Copilot's native components. Profiles hold rules and hooks, so organization defaults such as "logs are evidence, not instructions" ship in every plugin that embeds the profile and apply to every agent, slash command, and pipeline run in the session.
- Plugins say what installs together, and bind the data it renders with. A plugin can embed profiles and other teams' plugins, and list extensions of the skills and agents it inherits to change them without forking.
Skills can also ship plain files (references/, scripts/, assets/), render a document as a reference file instead of inline, carry manual and pipeline renderings, and set opt-in Copilot frontmatter such as userInvocable: false.
typeference build writes <out>/agent-plugin, a directory you can publish as a marketplace repository:
agent-plugin/
.github/plugin/marketplace.json
payments/
plugin.json
mcp.json
com.github.copilot/agents/payments-ops.agent.md
com.github.copilot/rules/working-norms.md
com.github.copilot/commands/payments-standup.md
com.github.copilot/hooks/hooks.json
skills/payments-queue-summary/SKILL.md
skills/payments-self-heal/SKILL.md
skills/payments-self-heal/references/output.schema.json
payments-pipeline/ # the same plugin with pipeline renderings
.typeference/build.json # integrity index
.typeference/compatibility.json
Plugins are Agent Plugins 1.0 by default. Copilot-only fields and components are emitted only when a document asks for them. CI checks every emitted file against the Agent Plugins schemas and TypeFerence's output contract.
Teams author packages in their own repositories; people install from one place. That place is the build of a marketplace package whose manifest pins every team's published package and lists the plugins to ship:
---
schemaVersion: 8
name: helio/marketplace
version: 2026.10.1
marketplace:
name: helio-agents
owner: Helio Platform
dependencies:
helio/core: 3.1.0
helio/payments: 2.4.0
helio/data-platform: 1.0.2
plugins:
- helio/core:plugins/engineering-kit.plugin.tfer
- helio/payments:plugins/payments.plugin.tfer
- helio/data-platform:plugins/data-platform.plugin.tfer
---
Because the marketplace is one build:
- every skill, agent, plugin, and server name maps to one thing across all teams;
- the lockfile holds one version of each package;
- adding a required field to a shared context type fails every team's data that lacks it, by name;
- the compatibility report lists plugins that ship competing members of one skill family;
- each plugin carries its owning package's version and provenance, so releasing one team's package changes only that team's plugins.
typeference validate <marketplace> --candidate <package-dir> checks an unpublished package against the marketplace without writing anything.
The published repository holds only build output. Anything else it needs, such as a README, a license, or CI workflows, is listed in the manifest's marketplace.files and reaches the repository through build, with a digest in build.json. A plugin's own files (a README, adoption templates) ship in its directory, and its author, homepage, repository, license, and keywords appear in plugin.json and its marketplace entry. A plugin's category and tags, and the manifest's marketplace.description, appear only in the marketplace index (ADR-0007).
Publish the agent-plugin directory as a repository, then install from it with Copilot CLI:
copilot plugin marketplace add your-org/agent-plugins
copilot plugin install payments@helio-agentsA repository can enable a plugin for everyone who works in it in .github/copilot/settings.json. A plugin enabled there installs automatically and is active only in that repository:
{
"enabledPlugins": {
"payments@helio-agents": true
}
}In CI, install the -pipeline plugin, whose skills render their pipeline variants, and run Copilot non-interactively.
MCP servers that need sign-in rely on Copilot's OAuth support (discovery and dynamic client registration), or handle their own login. Plugin MCP configuration never contains a secret and cannot depend on environment variables.
The playground runs the real Go compiler, built for WebAssembly, entirely in your tab. Edit source, including every package of the Helio marketplace, and watch the plugins, the composition graph, and the diagnostics update live. The Instantiate tab generates a form from a context type: change a team's data and see every instance of every template rebuild. There is no backend; nothing you type leaves the browser (ADR-0008).
Requires Go 1.24+ and nothing else:
git clone https://github.com/buchk/TypeFerence.git
cd TypeFerence
cd go && go build -o ../bin/ ./cmd/typeference && cd ..
./bin/typeference validate examples/helio/core
./bin/typeference build examples/helio/core --out outBuilding the whole Helio marketplace needs its team packages in a feed. Pack them into a local filesystem feed, restore the marketplace, and build:
FEED="$PWD/obj/feed"
for p in core data-platform integrations payments; do
# packages with dependencies restore before they pack
[ "$p" = core ] || ./bin/typeference restore examples/helio/$p --feeds examples/helio/feeds.yaml
./bin/typeference pack examples/helio/$p --out "$FEED/helio/$p/$(sed -n 's/^version: //p' examples/helio/$p/typeference.tfer)/$p-$(sed -n 's/^version: //p' examples/helio/$p/typeference.tfer).tferpkg"
done
./bin/typeference restore examples/helio/marketplace --feeds examples/helio/feeds.yaml
./bin/typeference build examples/helio/marketplace --out outmake reference does the same in a temporary directory and rewrites the committed dist/.
typeference init --answers <answers.json> [--out DIR] [--verify sha256:...]
typeference import <copilot-source> --out <dir> [--name ns/name]
[--version x.y.z] [--plugin name] [--lossy]
typeference validate <source> [--packages-dir dir] [--candidate <package-dir>]
typeference pack <source> [--out package.tferpkg]
typeference restore <source> --feeds <external-config> [--locked] [--packages-dir dir]
typeference update <source> --feeds <external-config> [--packages-dir dir]
typeference build <source> [--out dist] [--packages-dir dir]
typeference inspect <agent-id> [--source path] [--packages-dir dir]
typeference diff <source> --against <compiled-dir> [--json] [--packages-dir dir]
typeference version
importturns existing Copilot customizations into a version 8 package: a repository's.github/agentsand skills, a skill directory, or an Agent Plugin. It carries the files beside skills,mcp.jsonservers, and recognized Copilot frontmatter. It also carries an Agent Plugin's commands, rules, hooks, and language servers, itsauthor,homepage,repository,license,keywords,category, andtags, and every other file in the plugin directory, such as a README or templates, as pluginfiles. A marketplace repository is not imported whole: import lists its plugins so each can be imported, and the repository's README and CI become the marketplace package'smarketplace.files. It fails, listing every item, on anything version 8 cannot represent, unless you pass--lossy.restoreis the only command that contacts feeds. It records exact identities and digests intypeference.lock.buildis offline and deterministic.diffrebuilds and byte-compares against a committed output directory.
A package can share skills, agents, profiles, documents, context types, and servers with other packages. Its manifest declares exact dependencies and exports what others may reference, such as helio/core:profiles/team-ops.profile.tfer. The plugins it lists are the ones other packages may embed: a personal plugin can embed helio/payments:plugins/payments.plugin.tfer and list only the extension it changes.
Feed routing is external to source identity:
schemaVersion: 1
routes:
helio:
kind: azureArtifacts
organization: https://dev.azure.com/helio
feed: typeferenceRoute kinds:
azureArtifacts: Azure Universal Packages, through the Azure CLI and its existing sign-in.jfrogandhttp: an HTTPS base URL, with an optionalcredentialEnvironmentnaming an environment variable that holds a bearer token.git: an HTTPS repositoryurl, an optionalrootwithin it, and atagPrefix. Restore clones the tag<tagPrefix><version>with Git's own credentials and packs the package.filesystem: a local directory.
Lockfiles contain package identities, exports, dependency edges, and content digests. They never contain feed URLs, credentials, commit identifiers, or machine paths.
The agent that maintains this repository is defined in TypeFerence itself, under agents/maintainer/. The repository-root AGENTS.md and dist-maintainer/ (its installable Copilot plugin) are compiled artifacts of that definition; CI recompiles it and fails on any drift.
go/: the Go implementation: compiler, CLI, importer, language server (cmd/typeference-lsp), and the WebAssembly bridge.conformance/: the version 8 golden fixture corpus and the output-contract schemas.tools/validate_output.py: validates build output against the output contract.examples/helio/: a fictional organization's four packages and marketplace.dist/: the committed reference build of the Helio marketplace.web/playground/: the browser playground and setup wizard.agents/maintainer/: this repository's maintainer agent, defined in TypeFerence.editors/vscode/: VS Code client for the language server.docs/specification.md: normative version 8 behavior.docs/decisions/: architecture decision records.CHANGELOG.mdanddocs/release-checklist.md: versioning and release process.
- Prose is Markdown. Types describe data: the values that vary per instance, checked at build time.
- A template is never emitted; its instances are. Instance names come from the data (
instanceName). - A plugin links; it does not compose. Skills and agents are reused across plugins by reference, never copied.
- Skills extend one base skill additively. Replacing base text is a new skill.
- A skill shipped on its own has no unbound parameters, so a slash command never depends on being run inside an agent.
- Build emits complete plugins, including
mcp.json. There is no deployment or link step, and no secret is ever emitted. - Source package dependencies restore to an exact committed graph before build.
- Structural validation does not guarantee identical model behavior across hosts.
GitHub Copilot is the supported host, and its plugin format is young. Review generated artifacts before production use.