Skip to content

Publish a plugin

GitHub is the registry. Publish in your own public repository, then add the archon-plugin repository topic to appear in the plugin index. No Archon pull request, Archon account, or publication service is required. Listing is optional: archon plugin add owner/repo[/path][@tag] works independently of the index.

Place archon-plugin.json in your plugin root, either the repository root or a subdirectory. A repository can contain several plugins. Each manifest-bearing directory gets its own listing and install ID, such as acme/tools/packs/review-kit.

{
"schemaVersion": 1,
"kind": "workflow-pack",
"name": "review-kit",
"description": "Review workflows",
"compatibility": { "archon": ">=0.11.0" },
"entrypoints": { "review": "review/review.yaml" }
}

Use lowercase words joined by hyphens for name and entrypoint names. Each entrypoint path is <workflow folder>/<file>.yaml (or .yml), relative to the plugin root. Other workflows are support workflows and cannot be dispatched directly. See the pack layout and runtime identity.

The manifest is strict. Do not add version, credentials, install scripts, dependencies, or permission grants. compatibility.archon is optional; when supplied, installation checks it. Put prerequisites and usage instructions in a README.md alongside the manifest. The index links to the README on GitHub; it does not execute plugin code or embed author-supplied HTML.

Git tags are versions. For workflow packs, an untagged install resolves the default branch head and freezes its commit. Publish a tag to let operators choose a version:

Terminal window
archon plugin add acme/tools/packs/review-kit@v1.0.0

A forge plugin declares an executable instead of workflow entrypoints:

{
"schemaVersion": 1,
"kind": "forge",
"name": "example-forge",
"description": "Example forge integration",
"executable": "archon-forge-example"
}

Publish a GitHub release with <executable>-<os>-<arch> assets (.exe on Windows), and checksums.txt in sha256sum format covering the asset names. Supported platform names are linux, darwin, and windows; architectures are x64 and arm64. Build assets for the platforms you support. An untagged forge install uses the latest GitHub release. A tag without the required platform asset cannot install on that platform. Checksums detect damaged downloads; they do not establish publisher trust.

A provider plugin runs agent sessions in a separate process. Publish the implementation in your own repository with this manifest at its root or an installable subdirectory:

{
"schemaVersion": 1,
"kind": "provider",
"name": "example-provider",
"description": "Example agent provider",
"executable": "archon-provider-example",
"compatibility": { "archon": ">=0.11.1" }
}

The executable suffix is the provider id: archon-provider-example must return id: "example" in its descriptor. Publish release assets and checksums.txt with the same naming rules as forge plugins, for example archon-provider-example-linux-x64 and archon-provider-example-windows-x64.exe. Without @tag, install and update select the latest GitHub release.

Terminal window
archon plugin add owner/repo
archon plugin list
archon plugin update owner/repo
archon plugin remove owner/repo

Install verifies the checksum, starts the staged executable, validates its descriptor, and records that descriptor in the receipt. An invalid handshake, id collision, unsupported capability, or undeliverable API-key vendor leaves the previous install unchanged. Hosts register receipts without starting the executables at boot; each session checks the live descriptor against the installed one. Restart a running server after installing, updating, or removing a provider. A new CLI process sees it immediately. A workflow can then name the descriptor id in provider:.

Provider plugins execute code as your operating-system user. On the host they receive the ambient environment plus Archon’s per-request environment, just like an in-process provider. For container execution the plugin still inherits the host environment so it can launch the container runtime; the container request environment travels as session data and becomes the provider’s options.env. Credential checks use the plugin process environment. The process boundary supplies packaging, crash isolation, and cancellation; it is not a security sandbox. Archon withholds plugin stderr contents from its logs and errors because they may contain credentials or user messages.

Native tool specifications travel with the session; their handlers run in the host through _archon/tool_call. Calls after settlement or cancellation are rejected. serveProvider passes a structured log sink to its create(log) factory. Await that sink with { level, msg, bindings } to send metadata through _archon/log. The host logs provider.plugin.log at the supplied severity through provider.<id>, using its own descriptor id. Set bindings.failureClass to one of the contract’s failure classes on any record the operator should see; the host forwards that value and nothing else, and drops a record without a valid class. msg, plugin module identity, and all other bindings remain withheld. Never put credentials, tokens, or message text in log records. Keep stdout exclusively for RPC; configure other logging to stderr before it writes. Stderr remains withheld.

See building a community provider for serveProvider, descriptors, wire schemas, and conformance tests.

Provider receipts are additive, but older Archon binaries reject their unknown kind. Remove provider plugins before downgrading to a release without provider-plugin support.

Slack is the maintained in-repository example in packages/chat-slack. It uses @archon/chat-contract and Slack Bolt, without engine types or database access. Install it from an Archon release that publishes the Slack asset:

Terminal window
archon plugin add coleam00/Archon/plugins/chat-slack

Set SLACK_BOT_TOKEN and SLACK_APP_TOKEN in the server environment, then restart with archon serve. The plugin connects through Socket Mode; no webhook ingress is needed. Configure the Slack app with /archon and /archon-workflow, app_mentions:read, chat:write, reactions:write, commands, im:history, and users:read, plus the history scopes for the conversations you use. Subscribe to app_mention and message.im. The app token needs connections:write. Missing either token fails startup non-retryably.

The host reads SLACK_ALLOWED_USER_IDS and SLACK_STREAMING_MODE from the descriptor. It authorizes inbound traffic and run actions, resolves Archon users, and pushes typed run events. The plugin renders progress, decisions, reactions and cost footers. /archon connect github points to the Web UI or archon auth github; it does not run a GitHub device flow. Installing the Slack receipt replaces the bundled Slack transport and bridge on restart. Removing it restores the bundled adapter for this transition.

The plugin declares attentionNotices. A route’s destination is a channel id the bot has joined, or channel:thread_ts to post inside an existing thread. Each notice offers the gate’s decisions or the wait’s form as controls: a button per decision or option, a menu and Submit for a multi-select, and an answer modal for a message wait or a reply to an interactive loop, which needs Interactivity enabled in the Slack app. A wait without a pauseId offers Resume. A forbidden action is shown only to the member who clicked; a refused one, such as an answer to a pause that is no longer open, is posted in the notice’s thread. The run’s follow-up posts in that thread and, unless the plugin restarted since the notice, closes its controls.

The package tests run runChatConformance against the source process with a stubbed Slack client. Linux CI also compiles that entry point with test-only Slack and driver module substitutions and runs the same suite against the binary. The unmodified release binary is separately smoke-tested for credential-free initialization, non-retryable missing-token failure and shutdown. Compile binaries in CI, not locally on macOS.

A chat plugin declares an archon-chat-* executable:

{
"schemaVersion": 1,
"kind": "chat",
"name": "example-chat",
"description": "Example chat integration",
"executable": "archon-chat-example"
}

Publish release assets and checksums.txt with the same platform naming rules as forge and provider plugins, for example archon-chat-example-linux-x64 and archon-chat-example-windows-x64.exe. Do not put .exe in the manifest.

Terminal window
archon plugin add owner/repo@v1.0.0
archon plugin list
archon plugin update owner/repo
archon plugin remove owner/repo

Without a tag, install and update use the latest GitHub release. After checksum verification, Archon starts the staged executable, sends only initialize, validates its archon-chat/1 descriptor, and stops the process before recording the install. Initialization has a ten-second deadline and must work without chat credentials or chat/start. The receipt records the descriptor, release tag, commit, and binary digest. The descriptor’s platform id is independent of the manifest name and executable suffix.

The wire uses newline-delimited JSON-RPC 2.0 on stdin/stdout. For an initialize request such as {"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}, reply with the same request id and a descriptor as result:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocol": "archon-chat/1",
"id": "example-chat",
"displayName": "Example chat integration",
"version": "1.0.0",
"capabilities": {
"defaultWorkflowDispatch": "foreground"
},
"policy": {
"workspaceRetention": "age-based"
}
}
}

Write the response as one JSON line followed by a newline; the example is expanded for readability. Keep stdout for protocol messages. The generated chat contract schema defines ChatPluginDescriptor and the other wire payloads under $defs, including optional descriptor fields. TypeScript plugins can use serveChat from @archon/chat-contract to handle initialization and framing.

A platform id cannot belong to two chat installs. web, cli, api, github, gitea, and gitlab are reserved for host surfaces and bundled forge adapters. Collisions name both owners. A rejected initialization or collision leaves existing files unchanged; handled publication failures restore the previous install when the filesystem permits rollback. A rollback failure reports local recovery and backup paths, and a backup that stays locked past the retry window is named for you to remove. Installation does not promise crash atomicity across receipt and binary files.

Chat plugins run as your operating-system user and inherit the ambient environment. Plugin stderr and plugin-controlled error details are withheld because they may contain credentials or user messages. The process boundary is not a security sandbox.

Restart the server after installing, updating, or removing a chat plugin. The server starts one supervised process per usable chat receipt and verifies its live descriptor against the receipt. A receipt that is unreadable or does not own its executable starts no process and registers no platform policy; the server logs its path. Run archon plugin update <id> or archon plugin remove <id>, then restart. A matching installed platform supersedes its bundled adapter; for Slack, this also skips the bundled workflow bridge. The server logs that replacement. Without a matching receipt, bundled adapters continue to work as before.

The host enforces the descriptor’s allowlist for messages and run actions before creating an Archon identity. Run actions require the run’s starter or an admin. Run events go only to the plugin that owns the run’s conversation, for runs executing in the server process. Attention notices go to the chat routes configured in attentionNotices, for runs from any process. There is no webhook ingress for chat plugins.

A plugin that declares the attentionNotices capability receives chat/attention_notice for each configured route on its platform. The request carries the route’s destination unchanged and a typed notice: a gate with its decisions, an attention wait with its form and options, or a terminal follow-up for a run the route was told about. Return {conversationId} when the plugin can thread the follow-up there; the terminal request then carries it back. Answer an attention notice with the answer run action, naming the notice’s nodeId and pauseId and the chosen option ids. A wait without a pauseId paused before answers existed; continue it with the resume run action. The host refuses an answer to an occurrence that is no longer open, so a stale button reports the run’s current state instead of answering a later pause.

Crashes and retryable start failures restart with backoff from one to thirty seconds. A non-retryable start failure requires a server restart after correcting the configuration. Outbound requests time out after thirty seconds; two consecutive timeouts restart the process. Shutdown closes stdin and allows ten seconds for exit before terminating the recorded process tree. Plugin stderr and remote failure text are withheld from host logs. Remove chat installs before downgrading to an Archon release without chat receipts.

Add archon-plugin under your repository’s About topics. The site searches public repositories with that topic during each build and refreshes daily. It reads manifests from the default branch at one commit, even when the repository also has tags. The displayed latest tag is the first tag returned by GitHub’s tags endpoint; it is not a semantic-version ranking or a guarantee that a release asset exists. The install command without a tag follows the installer rules above.

Invalid manifests are skipped with their repository, manifest path, and validation reason in the site build log. Archived repositories remain visible with an archived flag. Listing is discovery, not endorsement or a code review. Maintainers can exclude a repository with a commit to packages/docs-web/plugin-denylist.json; entries are owner/repo, compared without case, and exclude every plugin in that repository. This affects listing only.

The build uses the read-only Actions GITHUB_TOKEN for GitHub API limits. Local site builds can use a token in GITHUB_TOKEN or make unauthenticated requests within GitHub’s public API limits. No token is required to publish or install a public plugin. GitHub API failures or incomplete search/tree results fail the build rather than replace the catalog with a partial listing.