Agent object model: .tfer format, typed context, tools, exposure, sealing, variants, LSP, and the Go-only pivot#9
Open
buchk wants to merge 32 commits into
Open
Agent object model: .tfer format, typed context, tools, exposure, sealing, variants, LSP, and the Go-only pivot#9buchk wants to merge 32 commits into
buchk wants to merge 32 commits into
Conversation
Formalizes the object model surfaced in the Obsidian-intersection design session: capabilities/skills/tools as contract/model-impl/code-impl, typed context as fields, and the governance primitives (exposure, sealing) that composition needs once it goes multiplayer. - 0012 (rev): mode variants gain per-variant requiresContextTypes; note the frontmatter-body vs multimodal cross-constraint - 0013 (rev): agents hold context / skills require context types; context types refine structurally; reference-by-id kills raw path refs; on-disk serialization deferred - 0014: Go-only pivot; spec stays normative-in-principle; conformance suite becomes a Go golden-file determinism suite (supersedes dual-impl parts of 0003/0004/0005) - 0015: exposure/visibility (Go export model; only exposed capabilities emit cards; private-by-default) - 0016: sealing/mutability/presence (sealed forecloses modification not extension; open-by-default; no special root) - 0017: tools as extern declarations; the capability/skill/tool trio; MCP crosswalk (our capability -> MCP tool) - 0018: callable-resource card as third ARD archetype; --emit-ard default; publish as an edge verb - 0019: two-doors context lifecycles (compile-time bake vs runtime query; user-written readers) All Proposed; no implementation yet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implements the .tfer serialization from the ADR batch and a v0 LSP. .tfer format (go/internal/resource): - loader walks .tfer alongside .yaml; each .tfer is YAML frontmatter + a verbatim markdown body split on `---` fences - body materializes onto the resource: a skill's instructions or a context object's content; bodyless kinds reject a non-empty body - new kinds `context` (instance; declares a contextType) and `contextType` (class; optional JSON Schema over frontmatter, may embed to refine) - reference-by-id groundwork; contextType/schema fields; .yaml still loads - validateShape split into a filesystem-independent validateDocumentShape so a single buffer can be checked without the whole source tree; CheckDocument is the diagnostic entrypoint Language server (go/internal/lsp, go/cmd/typeference-lsp): - JSON-RPC 2.0 over stdio; initialize/didOpen/didChange/didSave/didClose/ shutdown/exit; full-document sync - per-document authoring diagnostics via resource.CheckDocument (fence, unknown field, kind, binds, context/contextType shape errors) - v0 scope: single-file shape diagnostics only; cross-tree composition diagnostics (resolution, ambiguity, unsatisfied interfaces) are follow-up Tests cover the frontmatter split, body mapping, new kinds, .yaml/.tfer interop, and an LSP request/response round trip. Conformance suite still passes (byte-identity preserved). Makefile gains a build-lsp target. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wires ADR-0013 typed context and ADR-0017 tool declarations into the resolver. - contextType refinement via embedding: a type satisfies itself plus every type it transitively embeds (governedX embeds X -> satisfies both), with cycle detection - context objects held by id (`context:` on agents/profiles), promoted through embeds like context files - skills declare requiresContextTypes; checked at agent level against the union of held context objects' refinement closures (agent-level, not profile-level, so promoted requirements resolve once the agent supplies context) - new `tool` kind (extern declaration; interface schemas validated); skills declare requiresTools, checked to be declared at agent level - loader: new fields (requiresContextTypes, context, requiresTools, visibility) with kind-scoped validation; `tool` kind registered All additive and opt-in: existing resources set none of these fields, so compiled output and the conformance suite are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- capabilities carry visibility internal (default) or exposed; the resolver marks a bound skill Exposed from its capability's visibility - exposure rides the resolved skill, so it promotes through embedding onto the embedding agent's public surface automatically - ResolvedAgent.ExposedSkills() returns the public callable surface, from which a callable card (ADR-0018) is emitted rather than from every skill Private-by-default; existing resources declare no visibility, so output and conformance are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- skill bindings carry sealed/required; both ride the resolved skill through promotion - a sealed capability may not be overridden by a shallower binding or rebound locally: the resolver tracks sealedBy during promotion and errors on override or local rebind - extension is unaffected: adding adjacent capabilities alongside a sealed one resolves normally (sealed member, open container) Open-by-default; existing bindings set neither flag, so promotion behavior and conformance are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- skills declare either instructions (unimodal) or variants (mode -> {instructions});
the two are mutually exclusive and validated
- resolver carries a mode->instructions map and selects a default rendering
(prefer pipeline > manual > a2a, else alphabetically-first) into Instructions
- neutral bundle emits a variants member ONLY for multimodal skills, so
unimodal bundle output is byte-identical (conformance unaffected)
- .tfer body-as-instructions is rejected for multimodal skills (per-variant
instructions live in frontmatter) per the ADR-0012 cross-constraint
Per-target-surface variant selection in the target adapters (copilot->manual,
etc.) and per-variant requirement narrowing remain follow-ups; the default
variant renders across all targets today.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ostics Expands the language server beyond single-file shape diagnostics: - workspace roots captured at initialize; an id -> file index is built and refreshed on save - composition diagnostics: on open/save the whole workspace is resolved from disk (compile.Validate) and resolution errors (ambiguity, unsatisfied requires, sealing violations, undeclared tools/capabilities) surface on the file they name, or on the active file when unattributable; keystrokes stay fast with single-file shape diagnostics only - textDocument/completion: kind values after `kind:`, top-level field names - textDocument/definition: jump from a resource-id token to its defining file - textDocument/documentSymbol: the resource (kind + id) as a symbol - capabilities advertised accordingly Tests cover completion, token/symbol extraction, definition resolution, document symbols, and a composition diagnostic round trip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A worked corpus that compiles through the Go implementation and exercises every new construct together: an exposed capability, a multimodal skill (pipeline/ manual/a2a variants), a tool extern with requiresTools, contextType refinement satisfying requiresContextTypes, a sealed binding, context held by id, and a .tfer context note with a markdown body. Validates and builds clean; the three documented negative cases (drop held context, rebind the sealed capability, delete the tool) each fail with a precise diagnostic. Not wired into CI or the playground packer (both target examples/helio), so it is purely additive. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ADR-0014) Executes the Go-only pivot. The specification stays normative in principle; the Go compiler is the reference and only implementation. Determinism — the property behind diff and the committed-digest guarantee — is unchanged; only the second implementation and the cross-implementation half of the conformance suite go away. - remove src/ (C# compiler/CLI), tests/ (C# suite), TypeFerence.slnx, Directory.Build.props - CI: drop the dotnet build/test/conformance jobs; the conformance suite becomes a Go-only determinism suite; keep gofmt/vet/test/wasm, the diff-against-dist determinism check, the self-host drift gate, and the whitepaper docs job - release: drop the dotnet verify step - Makefile: remove build-dotnet/test-dotnet and the dotnet conformance/fmt steps - README, conformance/README: reframe as one implementation + a golden-file determinism suite - ADR-0014 marked Accepted; CHANGELOG updated Go tests, the helio determinism check, and the self-host drift gate all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
No .yaml resources remain under examples/helio. The 10 non-skill resources are wrapped as .tfer frontmatter (identical parse); the 4 skills move their instructions into the .tfer body, showcasing the format. Compiled bundles are byte-identical — only the ARD source-package entry changes, because it embeds the source files themselves (paths .yaml -> .tfer, media type, recomputed source digest). dist/ard/ai-catalog.json is regenerated to match; `diff examples/helio --against dist` reports no differences. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wrap the remaining .yaml resources as .tfer frontmatter; no .yaml resources remain anywhere under examples/. Validates and builds unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wrap agents/maintainer's 9 resources as .tfer frontmatter. The neutral bundle and the compiled root AGENTS.md are byte-identical, so the self-host drift gate (cmp AGENTS.md) still passes; only dist-maintainer's ARD source-package digest changes, regenerated here. No .yaml resources remain under agents/ or examples/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
--emit-ard now emits a third archetype alongside the source-package and precompiled-bundle entries: a callable-resource card per agent that exposes a capability. The card carries the fully-assembled invocation contract — each exposed capability's dispatch name, description, input/output schemas, and the instruction-package template — plus derivedFrom provenance to the source digest. Emitted only when an agent has an exposed capability, so agents with none add no entry: examples/helio (nothing exposed) is byte-identical and the determinism suite still passes. examples/repo-agent's exposed repository-status now produces a card. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- add ResolvedSkill.InstructionsFor(mode): a surface can select a variant's rendering, falling back to the default (ADR-0012) - the callable-resource card is the agent-to-agent surface, so it renders the a2a variant when a skill declares one (helio unchanged — no exposed caps, no cards; repo-agent's card now shows the a2a text) - mark ADRs 0012, 0013, 0015, 0016, 0017, 0018, 0019 Accepted (implemented) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…13/0012) - agents/profiles may declare allowedContextTypes; the effective list is the intersection of non-empty allow-lists through embeds (most restrictive ancestor wins). Held context must satisfy an allowed type via its refinement closure, else a build error. Empty = unrestricted. - variants may declare requiresContextTypes/requiresTools; a multimodal skill's effective requirements are the union of skill-level and every variant's (all variants are emitted, so the agent must satisfy each), checked at agent level and validated for id format at load. Additive/opt-in: no existing resource sets these, so helio stays byte-identical and conformance passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…0012) The neutral target emits one SKILL.<mode>.md per variant for a multimodal skill, alongside the default SKILL.md. Absent for unimodal skills, so their output is unchanged and helio stays byte-identical. repo-agent's repository-status now emits SKILL.pipeline.md, SKILL.manual.md, and SKILL.a2a.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- context objects may carry frontmatter fields beyond the standard keys; the loader collects them (other kinds stay strict — unknown key is still an error) - a contextType's schema enforces its required fields on the object; required fields accumulate across the refinement closure (a governed-cast object must satisfy cast-of-characters' required fields too) - repo-agent showcases it: governed-cast requires `owner`, notes/team carries `owner: Dana`; removing it fails validation Additive: schemaless contextTypes impose nothing, and no existing resource uses typed context fields, so helio stays byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A thin extension under editors/vscode that associates .tfer files (YAML frontmatter + markdown body) and launches typeference-lsp for diagnostics, completion, go-to-definition, and document symbols. - package.json (language + grammar contributions, vscode-languageclient dep), extension.js (stdio LSP client, configurable serverPath), a language-configuration and a TextMate grammar injecting source.yaml into the frontmatter and markdown into the body - verified as far as this environment allows: JSON valid, extension.js passes node -c, npm install resolves, vscode-languageclient loads (only the host-provided `vscode` module is unavailable outside the editor). Not yet run end-to-end in an editor — README says so. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
typeference publish <ard-dir> summarizes a compiled ARD catalog (source, bundle, and callable-card entries); with --registry it POSTs the catalog to a registry. Safe by default — a dry run without --registry, no network. This is the deployment edge, explicitly not the deterministic core: registry lifecycle is disclaimed by core semantics, so publish is an optional, side-effecting verb that a user invokes deliberately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes the emission half of typed context: a ResolvedAgent now carries its held context objects as (id, contextType) refs, and the neutral bundle emits a `context` array — conditionally, so agents holding none are byte-identical to before. Reference-by-id context is now visible in compiled output, not just resolved and type-checked. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Evolve the flagship example so it demonstrates v3, where the org's own behavior motivates each feature (not box-ticking): - exposure: repository-status, prepare-brief, and triage-message are the agents' public entry points -> visibility: exposed, so both agents emit callable cards - variants: payments-repository-status (the skill actually consumed a2a when prepare-brief calls payments-repo-agent.repository-status) is multimodal (pipeline/manual/a2a); the neutral bundle fans out per-mode SKILL.md and the callable card renders the a2a variant - tools: a repository-signals extern; payments-repository-status requiresTools it - typed context: safety-policy becomes a contextType (schema requires `authority`) and a held context object; triage-message requiresContextTypes it; enterprise- defaults holds it by id (dropping the old contextFile/slot); the bundle lists it - sealing: person-defaults seals the triage-message binding so an embedder cannot weaken the "do not send a reply" rule dist/ is regenerated; `diff examples/helio --against dist` is clean, the self-host gate is unaffected, and the eval dry run still runs. byte-identity was scaffolding during the build; the flagship example now teaches the features. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Context stops being a bibliography and starts being content. A resolved context ref now carries the object's displayName and body; renderInstructions inlines a "## Context" section into every target's agent doc, and the neutral bundle's context entries carry the content. Held typed context (e.g. helio's safety policy) now actually appears in the compiled AGENTS.md the agent reads, instead of being merely referenced — closing the emission half of typed context and the long-standing context-drift gap for context objects. dist regenerated; helio diff clean; conformance unaffected (agents holding no context objects are byte-identical). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ons to Copilot/Cursor (ADR-0012) Implements ADR-0012's target-driven variant selection and fixes a delivery gap the conceptual review surfaced: Copilot and Cursor rendered skill *descriptions* but never skill *instructions*, so those agents were under-specified. - variantForTarget: interactive/human surfaces (Copilot, Cursor, Codex) render the "manual" variant; the neutral bundle keeps the default and fans out. - Copilot/Cursor now inline each skill's instructions (manual variant) into their agent docs, since they have no per-skill SKILL.md mechanism. - Codex's SKILL.md renders the manual variant instead of the default. - fan-out lifted out of the Neutral special-case into a shared writeSkillFiles helper (altitude); dead renderSkill removed. This is a deliberate change to the Copilot/Cursor/Codex output contract, so the golden conformance digests for the 7 skill-bearing fixtures are regenerated and dist is rebuilt. helio diff clean; conformance green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The self-hosted maintainer's own context, capability, skill, and profiles still told it to run the deleted C# implementation (dotnet test TypeFerence.slnx, "both implementations", src/, tests/). The self-host drift gate could not catch this because dist-maintainer was regenerated from the same stale source. Rewrite the maintainer definition for Go-only + the golden-file determinism suite, recompile dist-maintainer and the root AGENTS.md, and drop the stale C# reference in the parity test's comment/name. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ed-diamond doc - remove the accidentally-committed go/typeference-wasm build artifact (7.5 MB) and gitignore it (and *.wasm) - requiredFields now errors on a schema whose "required" is present but not a string array, instead of silently enforcing nothing - pathToURI percent-encodes via url.URL, so workspace paths with spaces/reserved characters produce valid file URIs (go-to-definition no longer breaks there) - soften ADR-0016's "sealed diamond is fine" claim to note the resolver's pre-existing equal-depth ambiguity check rejects any diamond today Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Finishes two features the conceptual review flagged as nominal: - Typed context now checks field TYPES, not just required-presence. Context frontmatter fields carry their structural kind (scalar/sequence/mapping); validateContextFields checks each field declared in the contextType schema (and its refinements) matches — a scalar in an array-typed field, etc., is a build error. parseContextSchema reads both required and property types. - The callable card carries the WHOLE invocation surface, not just a2a: each tool keeps a2a as the default instructionsTemplate and now also carries every declared variant's template, and the card's data carries the agent's held context (id, contextType, content). A discovery consumer can invoke in any mode with the agent's context in hand. helio dist regenerated (richer card); conformance unaffected (no fixture exposes a capability, so none emit cards). Not done, and flagged honestly: conforming the card to the actual ARD / A2A Agent-Card schema a real agent finder consumes (needs the external spec), and card signing via the full trust config. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each tool entry in a callable card now carries requiresTools, so a consumer invoking the agent knows which extern tools it must provide — completing the invocation contract. helio dist regenerated; helio diff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Makes agents discoverable/invokable by real tooling, not just our proprietary
callable card. Per agent that exposes a capability, --emit-ard now writes under
ard/:
- <slug>.agent-card.json — an A2A Agent Card (a2a-protocol.org): protocolVersion,
name, description, version, url, preferredTransport, capabilities,
default{Input,Output}Modes, provider, and skills[] (one per exposed
capability). Because TypeFerence is definition-layer, the required
service-endpoint url is templated by convention (https://<domain>/a2a/<slug>);
the deployer serves the A2A endpoint there or overrides it.
- <slug>.mcp.json — an MCP tool manifest (modelcontextprotocol.io): each exposed
capability as an MCP tool with its input/output schemas embedded as JSON Schema
objects (not strings), directly loadable into an MCP server.
Emitted only for exposed agents, so the conformance fixtures (none exposed) are
unaffected; helio dist gains the four files. This is the piece that lets an agent
show up in an agent finder / stand up an MCP server from a compiled definition.
Still deliberately out of scope: signing the A2A card (JWS over the JCS-
canonicalized card) and per-tool auth/scope — flagged as follow-ups.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The ai-catalog.json we emit is structurally ARD-conformant (specVersion 1.0, host, entries with identifier/displayName/type + value-or-reference honored via data), but its entry media types were all proprietary (vnd.typeference.*), so an ARD registry would not recognize the resources as MCP servers or A2A agents. Per exposed agent, the catalog now also emits two entries in the official media types a registry indexes — application/a2a-agent-card+json and application/mcp-server+json — each embedding the resource as `data`, alongside the richer proprietary callable card. The A2A/MCP builders are shared with the standalone ard/<slug>.agent-card.json and ard/<slug>.mcp.json files. helio dist regenerated; conformance unaffected (nothing exposed in fixtures). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…y cards) Makes `compile an agent -> a pushable ai-catalog.json` real, per review feedback. Catalog is discovery, not fulfillment: - drop the proprietary vnd.typeference.callable-card entry entirely. The catalog now carries only standard-typed discovery entries per exposed agent — application/a2a-agent-card+json and application/mcp-server+json (each embedding the resource as `data`, value-or-reference honored) — plus the source-package and target-bundle provenance entries. - the fulfillment that lived in the card (a2a instructions template, every variant, required tools, held context) moves into the MCP manifest's x-typeference extension, so the .mcp.json stays a valid MCP file a generic client reads AND is the artifact a TypeFerence-aware server builds from. That is the definition-vs-deployment split: catalog discovers, server fulfills. Project manifest (the .slnx analogue): - new optional source-root `typeference.yaml` (schemaVersion, name, version, publisher), loaded and excluded from the resource walk like the trust config. - the ARD source-package identity/version now come from the manifest (not the folder name), and a declared `publisher` supplies the domain AND defaults ARD emission on — so `typeference build examples/helio` with no flags emits a pushable dist/ard/ai-catalog.json. - examples/helio gains a manifest; dist regenerated; helio + selfhost diffs clean; conformance unaffected (fixtures expose nothing). Follow-ups unchanged: A2A card signing (JWS/JCS), per-tool auth/scope. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Formalizes the latent object model of TypeFerence agents (ADRs 0012–0019), implements it end-to-end in Go, drops the C# implementation, migrates all sources to
.tfer, and evolves the flagship example to demonstrate it. Large, but every feature-commit is additive/opt-in so determinism stayed verifiable throughout.The object model
requiresTools)Modifier axes, all permissive-by-default with opt-in locks (per-axis Go defaults: open on override, private on export):
exposed— only exposed capabilities emit callable cardssealed— sealed forecloses override/rebind, not extensionrequiredWhat's implemented
.tferformat — YAML frontmatter + verbatim markdown body (skill instructions / context content); new kindscontext,contextType,tool.context:held by id,requiresContextTypes,allowedContextTypesgating (intersection through embeds), schema-directed required-field validation, and — new in the review pass — held context content inlined into the compiled artifacts so the agent actually receives it, not just a reference.toolextern kind;requiresToolscompile-checked; per-variant requirements unioned.variantson skills; the neutral bundle fans outSKILL.<mode>.md; each target renders a surface-appropriate variant (Copilot/Cursor/Codex → manual, neutral → default), and Copilot/Cursor now inline skill instructions they previously omitted.--emit-ardemits a third archetype (callable-resource card) per exposed-capability agent; the card renders the a2a variant.publish— deployment-edge verb: dry-run by default, POSTs with--registry.typeference-lsp) — shape + workspace-composition diagnostics, completion, go-to-definition, document symbols; plus a VS Code client undereditors/vscode/.Go-only pivot (ADR-0014)
Retires the C# implementation. The specification stays normative-in-principle; the cross-implementation conformance suite becomes a golden-file determinism suite over the same fixtures. Determinism (the property behind
diffand the committed digests) is unaffected — only the second implementation went away. CI, release, Makefile, README, and the self-hosted maintainer definition are updated to Go-only.Migration & example
.yamlresources remain underexamples/oragents/— all migrated to.tfer(skills carry instructions in the body). Compiled bundles were byte-identical; only ARD source digests changed.payments-repository-status(the a2a-consumed one), arepository-signalstool, a typedsafety-policycontext (schema requiresowner…authority), and a sealed triage binding.Reviewer notes
requiredFieldsswallowing errors,pathToURIencoding, an ADR-0016 diamond overclaim).examples/repo-agentnow that helio covers everything; cache LSP composition diagnostics; the VS Code extension is verified as far asnpm install/node -cbut not run in-editor.Gates: gofmt-clean,
go vet, all 7 test packages, helio + self-host determinism (No differences), wasm/playground build, eval dry run.🤖 Generated with Claude Code