Installing
axon install @axon/discord
axon i @axon/discord # same thing, shorter
Run from your agent directory. One command for every kind — the name resolves to exactly one artifact, so nothing tells the CLI whether it is fetching a module or a prompt.
What lands depends on what it is. A module's source goes to
node_modules/@axon/discord/, its npm dependencies merge into your agent's
package.json, and the CLI lists any env keys it needs. A prompt package is
declared in prompts: and its prompts become invokable by name.
Run axon prepare after installing anything, to regenerate type declarations.
Installing a prompt
axon install @cody/eslint-scout
The package is added to prompts: in your agent config, and every top-level
.vue/.md it ships becomes an invokable prompt namespaced by the package:
axon run @cody/eslint-scout:scout
A package shipping exactly one prompt named after itself also answers to the
bare name, so @cody/scout need not be written @cody/scout:scout.
The namespace is what stops an installed prompt shadowing one you wrote. Your
own src/prompts/scout.vue stays scout; the installed one is
@cody/eslint-scout:scout. They occupy different namespaces by construction,
not by a precedence rule you have to remember.
Configuring env keys
Modules declare the env keys they require. After install, add them to your
agent's .env:
DISCORD_BOT_TOKEN=your-bot-token-here
The CLI prints exactly what's needed and why. Nothing is set automatically — you provide the values.
Prompt packages never need this. They are text, so there is nothing to authenticate.
Configuring options
Modules can expose options that control their behaviour. modules is an
array; pass options with a [module, options] tuple:
export default defineAgent({
modules: [
["@axon/discord", { mentionOnly: true, channelIds: "1234567890,0987654321" }],
],
})
Options are declared by the module with types and defaults. Run axon prepare
after installing to get type declarations — your editor will tell you exactly
what's available.
Subscribing to hooks
Most integration modules emit hooks when external events arrive. You subscribe in a server plugin:
// server/plugins/discord.ts
export default defineAxonPlugin(async (axon) => {
axon.hooks.hook("discord:message.received", async ({ content, username, reply }) => {
const prompt = await axon.prompt("discord/discord", { content, username })
const result = await axon.request({ prompt })
await reply(result.text)
})
})
The hook payload is typed from the module's emits declaration. Your editor
knows what fields are available.
Using contributed tools
Modules contribute tools under their namespace. After axon prepare, they are
fully typed on axon.tools:
// In a script or route handler
const pr = await github.openPr("fix: auth", body, "feat/auth")
const issues = await kanban.list({ status: "open" })
Run axon prepare any time you install or update a module to regenerate type
declarations.
The full install flow
axon install @axon/discord # fetch source, add deps, print env requirements
# add DISCORD_BOT_TOKEN to .env
axon prepare # regenerate types
Then add a plugin to subscribe to hooks, and the agent is live.
For a prompt, there is no second half:
axon install @cody/eslint-scout
axon run @cody/eslint-scout:scout