Aller au contenu

Maia extensions

Status: planned (S73, and S61 as the first Maia extension). The roadmap owns order and entry conditions; the open choices are in D-114. "Maia extension" is distinct from Pi's own extensions: Pi's built-in codemode, llama.cpp, MCP and tool-search extensions never load (D-067), and a Project's own Pi extensions load only in maia agent, pinned by digest in .maia/maia.json.

A Maia extension packages things Maia already has so a Workspace can add them in one reviewed step. It contributes bounded capabilities and never becomes another authority. This document defines the provenance, compatibility, capability scoping, confirmation, isolation, rollback and audit contracts that AGENTS.md requires before Maia loads any extension.

What an extension may contribute

Every part is optional, and each maps to an existing primitive:

PartPrimitiveHow it becomes active
SkillsSkillsLoaded progressively by Agents granted the extension
Agent templatesAgents (S49)A person creates an Agent from one; it is then a copy
Routine templatesRoutines (S50)A person creates a Routine from one; it is then a copy
RulesWorkspace rules (S54)Proposed in the install preview; added only if confirmed
Tool serversTool connections (S71)Admitted by digest; granted per Agent; allow, ask or off
Event sourcesEvent triggers (S51)Post typed events with their own revocable credential
A serviceSandboxed process (S47)Runs as an ORG3 service account with exact grants
Sandbox providerRemote sandbox (S47f)Maia verified only; an Agent or step names it as placement
Eval rubricsEvals (S62)Added as named Workspace evals

An extension may not add a protocol operation, a Connection kind, a model tool outside its tool servers, Node code, a client view or a grant. A new operation or credential kind is a Node change through the protocol registry, as for every feature. A service uses only public SDK operations under its service account, so it can read and write what its grants allow and can never confirm. A sandbox provider is a service implementing the Node's fixed sandbox provider contract (S47f), not Node code.

Package

An extension is a directory or archive with a maia-extension.json manifest and the files it names. Its identity is name, version and the SHA-256 digest of the canonical archive. The manifest declares:

  • the Maia protocol range it needs and the Node operations it calls;
  • every part above, with each file's digest;
  • for each tool: its name, risk class (read, write or destructive) and the default mode (ask for anything above read);
  • network hosts, Connection kinds it uses (never creates), event kinds and the grants its service needs.

Contents are inert data. Tool servers and services are digest-pinned executables or images that run only inside S47 sandboxes. Each part carries the same identity and digest fields as feature contributions and the admitted Project snapshot (ResourceProvenanceV1 in the Agent architecture), so admission has one vocabulary and no second package format.

The seven contracts

  • Provenance. Install from the Maia release channel, a Git URL at an exact commit, or an archive by digest. A tag or branch is resolved once and pinned. Three trust levels show everywhere: Maia verified (built in this repository, passing the conformance suite in CI, signed with release provenance under E1), Reviewed (passed the directory review) and Unreviewed (local or a Git URL). A Workspace policy (E5) chooses which levels it allows, plus an allowlist of publishers or digests; an organization's default allows verified and reviewed ones, and an unreviewed one needs an admin's allowlist entry.
  • Compatibility. Install fails closed if the Node lacks an operation, Connection kind or protocol minor the manifest needs, naming each. The RL2 handshake rules apply on Node updates; an extension that becomes incompatible is disabled with a reason, never half-running.
  • Capability scoping. The install grants at most what the manifest declares, and the person may grant less. An Agent gets an extension's tools only through its own grants (S2, S71). Credentials reach a tool server or service only through S47 providers on declared hosts; values never enter model context, files, logs or receipts. A Project may narrow an extension but never widen it.
  • Confirmation. Install, enable per Workspace or Project, upgrade, disable, rollback and archive each preview and need a person's confirmation with a receipt. The preview lists every Skill, template, rule, tool with its risk class, host, Connection kind, event kind and service grant. An upgrade previews the difference, lists any widened capability first and is never automatic.
  • Isolation. No extension code runs in the Node. Tool servers run in the Session's sandbox or as remote endpoints on their own Connection; a service runs in its own sandbox with only its declared hosts and the Node's approved endpoint. Nothing reaches the Node's database, files, other Sessions or a person's credentials.
  • Rollback. The previous version stays installed; rollback returns to its digest under the same preview and confirmation. Disable stops tool calls, event sources and the service at once and keeps everything else; archive replaces deletion. Agents and Routines created from templates are the Workspace's own revisions and survive any of these. An S20 capability hold on an extension stops it within S20's bounds.
  • Audit. Every lifecycle change, tool call (S71) and event names the extension's name, version and digest; the audit log (E2, ORG5) can filter by extension.

Operations and CLI

extension.install.preview and confirm, extension.enable, extension.disable, extension.upgrade, extension.rollback and extension.archive (each as preview and confirm), extension.list, extension.show and extension.check. CLI first: maia extension plan <source>, maia extension apply <plan-id>, maia extension enable <name> --project <id>, disable, upgrade, rollback, list, show, and maia extension check <path>, which runs the conformance suite locally. The personal agent (S67) can preview any of these; a person confirms.

Authoring

Creating an extension takes one command and no setup beyond the CLI:

  • maia extension new <name> asks which parts to include and writes a folder with the manifest, each part, tests, three evals per Skill, a README and a license. A tool server starts from a TypeScript template on the extension kit (manifest types from the protocol, an MCP stdio server and a test harness on Effect); any language that speaks MCP over stdio works.
  • maia extension dev <path> installs it as Unreviewed into the person's own dev Project, never a shared scope. With S73a it loads Skills, templates, rules and evals; tool servers, event sources and services load once S73b and S73c ship. The person confirms a capability envelope once; each saved change becomes a new digest and reloads within that envelope without asking again, while a change that widens it pauses until the person confirms. Tool calls, events and service logs stream to the terminal, and maia extension test runs the evals and recorded scenarios.
  • With Maia itself: the personal agent hands the work to an Agent from the extension builder template, which writes the extension from a description with its maia-extension-author Skill in a sandboxed worktree, runs check and the tests there, and proposes the dev install; the person confirms its envelope. An agent never publishes, enables beyond the dev Project or widens an envelope.
  • maia extension pack makes a deterministic archive and digest; maia extension publish opens the directory submission, through the GitHub extension when installed.

Directory and review

The public directory lists extensions anyone can install, and admits them only through a full review, because a listed extension reaches many Workspaces at once.

  • Index. A public Git repository holds one entry per extension: publisher namespace, name, version, HTTPS source repository, exact commit, archive digest, declared capabilities and license. Each pull request adds or updates exactly one extension; the source stays in the author's repository, and the directory's CI builds the archive from the pinned commit and attaches it, signed, to a release. Maia verified extensions enter the same index from this repository's release CI. An open-source author may also propose an extension into this repository by pull request; maintainers adopt it as Maia verified only when they will maintain it. The public site renders the directory from the index, so the directory adds no hosted service.
  • Publisher identity. A namespace is proven by a GitHub account or organization through workflow identity, or by a DNS challenge. Publishing needs a passkey or second factor, comes from the source repository's CI with a short-lived workflow identity rather than a stored token, and carries a provenance attestation binding the archive digest to the commit and workflow. Provenance proves where a build came from, not that its publisher was not compromised, so it never replaces review.
  • Automated gate (every pull request). The manifest validates; the build from the pinned commit reproduces the digest; a lockfile is present and no install script, runtime code download, obfuscated or minified source ships; dependencies pass vulnerability, typosquat and license checks; a secret scan finds nothing; Skill text is scanned for hidden Unicode, instruction overrides and fetch-and-run instructions; the conformance suite and the S47 escape suite pass; a recorded scenario run in a sandbox observes no host or tool beyond those declared.
  • Model-assisted review. Several models read the change and flag suspicious behavior; a flag routes to people, and no model approves.
  • People by risk. Skills, templates and read-only tools need one maintainer; write tools, a service, credentials or more than one network host need two, one of them from security; a publisher's first listing always needs two.
  • Updates. Every version is a new pull request showing its capability difference; any widening repeats the review for its tier. A reviewed update is listed at once and marked new for 72 hours, while advisories and reports can still revoke it; no Node installs an update without a person's confirmed upgrade.
  • Listing. Each page shows the publisher, trust level, capabilities in plain words, the last review date, versions, active installs and open reports. Featured collections are curated by maintainers; ranking and any paid promotion are an owner decision (D-114).
  • After publication. Every listed version is rescanned against new advisories daily, and anyone can report one. A signed revocation feed, checked by each Node daily and on connect, disables a revoked digest at once, as an S20 hold does, with a receipt and an attention item; a compromised publisher can have every version revoked, and an ownership transfer repeats the publisher's first-listing review.

Conformance suite

Every Maia verified extension passes it in CI, and anyone can run it on a third-party extension; a passing report is recorded but grants no badge.

  • The manifest validates against its schema, and every file matches its digest.
  • Every tool call and host observed in a recorded scenario run is declared, and every declared write tool defaults to ask.
  • The S47 escape suite passes for each tool server and service.
  • Each Skill has at least three evals, as S22 requires.
  • Disable, rollback and archive leave no running process, tool or event source.

GitHub extension (S61)

Agents get GitHub data and actions through Maia, never through a person's gh or Git credentials. S61a ships the Node part and GitHub operations through the CLI, SDK and maia mcp first, so the production migration does not wait for extensions; S61b then packages the rest as the first Maia verified extension.

  • Node part (built in). S61 adds the GitHub App Connection kind to the Node through the protocol registry: one App per Workspace, created by a guided manifest flow from the CLI, its private key in the managed secret store (E2a, D-010), or until then in an owner-only file in the Node root as S24 keeps gateway keys, and the App ID reserved for one Workspace only. Owners are pinned by numeric account ID. The Node mints each installation token for one repository and the permissions that call needs. Only read tokens reach the sandbox, through S47 providers. A write identity policy per Workspace chooses the App bot or a named person's App user token, which that person confirms; worker launches never carry a person's gh or Git credentials.
  • Write boundary. Every GitHub write, Git push included, is a Node operation; no write-capable token ever reaches a sandbox. Before it attaches a credential, the Node checks the caller's current grant for that tool, repository and ref. For a push it inspects the pushed commits for the paths and workflow files its policy protects (D-124) and binds the push to the expected remote head by compare-and-set. Each write carries an idempotency key and leaves a receipt, so a raw shell, API or Git call from the sandbox has no write credential.
  • Extension part. Tools for repositories, issues, pull requests, reviews, checks, labels, milestones and organization Projects (reads allow, writes ask); Skills for triage, review and release notes; Agent templates (reviewer, triager); Routine templates (review each new pull request with one reviewer per perspective, daily triage, follow up a failed check); and a service that keeps issues and pull requests linked to S53 tasks, with GitHub as their source of truth. Events arrive by signed webhooks when the Node has approved public ingress, and otherwise by polling with conditional requests, so a private Node needs no public route.
  • Safety. GitHub writes are Workspace configuration, like Skills, Agents and tool access (D-116). A person grants each write tool (open a pull request, comment, label, review, merge) to exact Agents for exact repositories, the repository's branch protection enforces checks and reviews, and an ungranted write asks a person. There is no admin merge. A write to a path or workflow file that the policy protects needs its own grant (D-124); a lost response stays outcome-unknown until the next read settles it.

Acceptance

  • An extension needing an operation the Node lacks is refused before install, naming it; a third-party extension is refused where policy allows verified only.
  • An install preview lists every declared part; confirming installs exactly that, and an upgrade that widens a capability waits for a new confirmation.
  • A tool server calling an undeclared host is blocked; a service's credential cannot confirm or exceed its grants; no credential value appears in model context, transcripts, logs or receipts.
  • Disable stops every tool, event source and service within S20's bounds; rollback restores the previous digest; templates' copies survive both.
  • GitHub: an agent with no grant gets no GitHub token; a token minted for one repository is refused on another; with a valid grant for one tool, a raw shell push, a direct API write and a push touching a protected path from the sandbox are each refused and none reaches GitHub; a push whose remote head moved is refused; an ungranted merge or pull request asks a person; a granted merge is refused once its grant is revoked, when the head changed since the checks passed, or when branch protection fails; a Node with no public route still receives changes by polling.
  • maia extension new, then dev, gives a working local extension with no other setup, for inert parts with S73a and for executable parts with S73b and S73c; a saved change within the envelope reloads without a prompt, and a widening change waits for the person.
  • A directory pull request whose build does not reproduce its digest, or whose sandbox run observes an undeclared host or tool, cannot merge; a widening update is not listed without its tier's review; no update installs without a person's confirmation; a revoked digest is disabled on every connected Node at its next check.

Imported from Maia OS docs at 3dc3e07