# AEOS Playbook

**Purpose:** Operational guide for building, publishing, and maintaining AEOS-conformant extensions in the Axiom portfolio
**Audience:** Extension authors (humans and agents), maintainers, platform engineers
**Last Updated:** 2026-04-21
**Authoritative documents:** [spec-aeos-0.1.md](../specs/spec-aeos-0.1.md), [ADR-031](../adrs/adr-031-extension-self-containment.md), [ADR-032](../adrs/adr-032-standards-positioning-dual-track.md)

---

## TL;DR

- Every Axiom-ecosystem extension conforms to AEOS (Agent Extension Open Standard)
- AEOS is an internal specification (ADR-032 dual-track) — public-facing for Axiom contributors, not publicly promoted until a strategic decision
- Extensions are purpose-named (no type suffixes) and scaffolded as compound by default
- Seven capability kinds: agent, tool, cmd, service, adapter, skill, hook
- Signed releases via Sigstore; `axi ext` CLI for every lifecycle operation
- Federation-native features (attestation, quarantine, governance) are Axiom's leap-ahead

---

## Creating a New Extension

```bash
axi ext init my-extension
cd my-extension/
```

`axi ext init` scaffolds the canonical compound layout. You get every capability-kind subdirectory; populate the ones your extension actually uses.

### Pick your kinds

Ask yourself: what does this extension do? Answer drives which subdirectories you populate:

| Need | Populate |
|---|---|
| Autonomous LLM-backed component with state | `agents/` |
| Stateless callable for agents or CLI | `tools/` |
| CLI noun/verb group on `axi` or `neut` | `commands/` |
| Long-running daemon | `services/` |
| Third-party integration (LMS, IdP, etc.) | `adapters/` |
| SKILL.md natural-language skill | `skills/` |
| Lifecycle interceptor | `hooks/` |

Delete unused subdirectories. Declare what you keep in `axiom-extension.toml` via `[[extension.provides]]` blocks.

### Declare capabilities

Every capability you provide gets a manifest block:

```toml
[[extension.provides]]
kind = "tool"
name = "syllabus_extraction"
entry = "my_extension.tools.syllabus_extraction:SyllabusExtractor"
description = "Extract course structure from syllabus"
idempotent = true
```

The `entry` field maps to a Python entry point in `pyproject.toml`. `axi ext lint` verifies they match.

### Define your public API

Every extension's `__init__.py` declares `__all__`:

```python
from my_extension.tools.syllabus_extraction import SyllabusExtractor
from my_extension.agents.my_agent import MyAgent

__all__ = ["SyllabusExtractor", "MyAgent"]
```

Only these symbols may be imported by other extensions. Everything else is private (prefix with `_` or place in `_internal/`). `import-linter` enforces.

---

## Standard Development Loop

```bash
# Develop
axi ext dev               # Watch mode; hot-reload on save
axi ext run <name>        # Invoke capability directly for smoke-testing

# Quality
axi ext lint              # Layout + manifest + imports + entry points
axi ext test              # Run tests via axiom-tests plugin
axi ext validate          # Load extension, run standard test suite, verify declarations

# Visualize
axi ext studio            # Visual playground (post-Prague)
axi ext graph             # Dependency visualization
axi ext show <name>       # Full metadata view

# Doctor and diagnose
axi ext doctor            # Health check with remediation hints
axi ext scan              # Static security analysis (Dendra-classified)
```

Write tests against `axiom-tests` base classes:

```python
from axiom_tests.unit_tests import ToolTests

class TestMyTool(ToolTests):
    @pytest.fixture
    def tool_class(self):
        from my_extension.tools.my_tool import MyTool
        return MyTool
    
    @property
    def supports_streaming(self) -> bool:
        return False
```

Standard tests inherit from capability-kind base classes. Override capability properties to declare what your extension supports. Missing behaviors against declared capabilities fail the standard test — forces honesty in your manifest.

---

## Publishing

```bash
# Pre-publish verification
axi ext lint
axi ext test
axi ext validate
axi ext sign                 # Sigstore keyless signing

# Publish
axi ext publish              # To Vyzier (primary) or PyPI (fallback)
```

Publishing requires:
- All tests passing
- `axi ext lint` clean
- Sigstore signature (mandatory — no unsigned extensions accepted by default registries)
- Publisher identity matches `[extension.signing].publisher_identity` in manifest

Trusted Publisher (PyPI OIDC) eliminates API tokens — GitHub Actions authenticates via OIDC, Sigstore issues a short-lived certificate, signed artifact lands in registry.

---

## Installing and Maintaining

```bash
# Install
axi ext install my-extension           # from Vyzier
axi ext install my-extension --registry pypi    # force PyPI
axi ext install my-extension --allow-unsigned   # emergency escape (not recommended)

# Lifecycle
axi ext list                  # Installed extensions, versions, status
axi ext search <query>        # Discover in registry
axi ext update [<name>]       # Update one or all; respects version pins
axi ext uninstall <name>      # Remove, preserving audit trail

# Configuration
axi ext config <name> get     # View current settings
axi ext config <name> set key=value
```

Signature verification is automatic on install. Verification failures abort install with clear error.

---

## Capability Kinds — Quick Reference

### agent

LLM-backed, persistent identity, state across sessions. AXI naming convention.

```toml
[[extension.provides]]
kind = "agent"
name = "my-agent"            # Used as principal identity
entry = "my_ext.agents.my_agent:MyAgent"
persona = "my_ext/agents/my_agent/persona.md"   # Agent's own system prompt (NOT a standalone skill)
requires_signals = ["signal_1", "signal_2"]
uses_skills = ["some_skill", "another_skill"]   # Standalone skills this agent may invoke
```

Note: the `persona.md` file defines what *this specific agent* is — its role, allowed behaviors, tone. It is internal to the agent. Do NOT confuse it with a standalone skill (see `skill` kind below). If an agent needs reusable instructions available to other agents too, put those in the `skill` capability, not in the agent's persona.

### tool

Stateless callable. Input + output schemas.

```toml
[[extension.provides]]
kind = "tool"
name = "my_tool"
entry = "my_ext.tools.my_tool:MyTool"
idempotent = true            # Can be safely retried
side_effects = "none"        # or "writes_file", "calls_network", etc.
```

### cmd

CLI noun for `axi` or consumer CLI.

```toml
[[extension.provides]]
kind = "cmd"
noun = "my_noun"
entry = "my_ext.commands.my_noun:cli"
subcommands = ["add", "list", "remove"]
```

### service

Long-running daemon.

```toml
[[extension.provides]]
kind = "service"
name = "my_service"
entry = "my_ext.services.my_service:MyService"
deployment_profile = "edge"  # or "workstation", "server", "platform"
```

### adapter

Third-party integration. Wraps a REST/GraphQL/etc. service.

```toml
[[extension.provides]]
kind = "adapter"
integration = "my_provider"
entry = "my_ext.adapters.my_provider:MyAdapter"
auth_methods = ["oauth2", "api_token"]
capabilities = ["read", "write", "subscribe"]
```

### skill

agentskills.io SKILL.md skill. Directory-based. **Standalone and reusable — NOT tied to any specific agent.** Any agent with access may invoke it.

```toml
[[extension.provides]]
kind = "skill"
name = "my_skill"
path = "my_ext/skills/my_skill/"
description = "What this skill does; invokable by any agent with access"
```

The `path` points to a directory containing `SKILL.md` + optional scripts/references/assets.

**Scoping:** If you want LLM instructions attached to one specific agent, put them in that agent's `persona.md` (see the agent capability above) — not here. Use the `skill` capability only for instructions that should be reusable across agents or across tasks. If multiple agents will need the same instructions, it's a skill; if only one agent will use them and they define that agent's identity, it's a persona.

### hook

Lifecycle interceptor.

```toml
[[extension.provides]]
kind = "hook"
events = ["session.started", "session.ended"]
entry = "my_ext.hooks:session_hooks"
priority = 100
fail_mode = "warn"           # or "abort", "ignore"
```

---

## Cross-Extension Dependencies

Extensions depend on:
- **Axiom core** via `from axiom import ...` (`[[extension.consumes]] kind = "core"`)
- **Other extensions** via their public API only (`[[extension.consumes]] kind = "extension"`)
- **Dendra-backed classifiers** when using LearnedSwitch semantics (`[[extension.consumes]] kind = "dendra"`)

```toml
[[extension.consumes]]
kind = "extension"
package = "vega-trust"
version = ">= 0.1, < 0.2"
capabilities = ["federation", "trust_profile"]
```

`axi ext lint` verifies:
- Declared dependencies are installed or resolvable
- Imports in source respect public-API-only rule (import-linter enforced)
- No cross-extension private imports

Violations block publish.

---

## Federation (AEOS Leap-Ahead)

If your extension should travel across institutional boundaries:

```toml
[extension.federation]
shareable = true                   # Opt in to manifest-channel distribution
requires_attestation = true        # Need behavioral attestation to activate on receiver
quarantine_recoverable = true      # Support recovery ceremony
```

Share an extension across federation:

```bash
axi ext federate my-extension --to triga-consortium
```

This signs the extension with your node's federation identity, publishes to the federation manifest channel, and notifies peers. Peer nodes verify signatures, apply local trust profile, and activate if compatible.

---

## Attestation (AEOS Leap-Ahead)

Behavioral attestation is the Axiom leap-ahead: "does this extension actually do what it claims?"

```bash
axi ext attest my-extension        # Generate Dendra-backed attestation
```

The runtime observes the extension's actual behavior over a configurable window (default 7 days of invocations), compares to declared capabilities, and issues a signed attestation. Receivers in federation use attestations for trust decisions.

Quarantine triggers automatically when observed behavior diverges from declared capabilities beyond threshold:

```bash
axi ext quarantine my-extension    # Manual quarantine (or auto-triggered)
axi ext recover my-extension       # Initiate recovery ceremony
```

Recovery requires the publisher to re-sign with an updated attestation; the runtime re-verifies before lifting quarantine.

---

## Conformance Levels

Every published extension gets a conformance level from `axi ext lint`:

- **Bronze:** compatible layout + manifest + required files + Tier 1+2 CLI operate
- **Silver:** Bronze + Sigstore signed + ≥80% test coverage + public API enforced
- **Gold:** Silver + attestation-capable + quarantine-recoverable + federation-shareable + trust-profile-declared

Production deployments requiring classification > "public" MAY require Gold conformance.

---

## Migrating Existing Extensions

Per ADR-031 Phase 2 migration. For each existing extension:

```bash
axi ext migrate <current-location> --target <new-name>
```

The migrate command:
1. Moves related docs from `axiom/docs/` to extension's `docs/`
2. Moves related tests to extension's `tests/`
3. Renames to purpose-name (strips legacy `_agent` or other type suffix)
4. Generates `axiom-extension.toml` from observed code
5. Creates `README.md`, `CHANGELOG.md` from templates
6. Runs `axi ext lint` to verify conformance

Migration happens as one PR per extension. Order (least risky first):
1. `diagnostics/` → `triage/`
2. `connect/` (stays; already purpose-named)
3. `memory/` → `memory/`
4. `hygiene/` → `tidy/`
5. `publishing/` → `press/`
6. `signals/` → `scan/`
7. `chat/` → `neut/` (in NeutronOS repo)
8. `classroom/` (stays; becomes `keplo` post-extraction)

---

## Standards Alignment

Per ADR-032 dual-track strategy, AEOS extensions are simultaneously compatible with:

- **MCP** — tools within the extension expose as MCP tools
- **MCPB** — extension bundles are MCPB-installable for MCP-only clients
- **A2A** — agents publish A2A Agent Cards
- **SKILL.md / agentskills.io** — skill capabilities use SKILL.md format verbatim
- **AGENTS.md** — extension repositories carry AGENTS.md
- **OpenAPI 3.1** — adapters wrapping REST services embed OpenAPI
- **Sigstore / PEP 740** — all releases signed
- **Semantic Versioning 2.0.0** — all versions
- **Keep a Changelog** — all CHANGELOG.md files

Don't invent where a standard exists. Extend when AEOS features go beyond.

---

## Anti-Patterns to Avoid

- **Type suffix in name** (`my_agent/`, `my_tool/`) — purpose-named only, type in manifest
- **Cross-extension private imports** — import-linter blocks these
- **Mutable updates without re-signing** — every release is a new signed artifact
- **Skipping standard tests** — `axi ext lint` refuses to lint without them
- **Overridden Tier 1 commands without justification** — possible but confuses users
- **Skill without SKILL.md YAML frontmatter** — fails agentskills.io validation
- **Manifest capability declaration without matching Python entry point** — `axi ext lint` catches this

---

## Tooling Tiers — Availability Summary

| Tier | Commands | Availability |
|---|---|---|
| **Tier 1 (Lifecycle)** | init, install, uninstall, update, list, search, show, templates | Required; ship with Axiom |
| **Tier 2 (Quality)** | lint, validate, test, doctor, docs, config, publish, sign, verify, scan, graph, run, eval, migrate | Required; ship with Axiom |
| **Tier 3 (DevX)** | dev, studio, replay, trace, bench, train, deploy | Strongly recommended; studio deferred post-Prague |
| **Tier 4 (Leap-ahead)** | federate, attest, quarantine, recover, evolve, govern | Axiom-exclusive; require federation/Dendra/Vega |

---

## When in Doubt

- **Naming:** is it a product (normal case) or an agent (ALL-CAPS-HYPHEN)?
- **Layout:** does it match the canonical compound structure in §5.1 of the AEOS spec?
- **Public API:** is every cross-extension-visible symbol in `__all__`?
- **Capability declaration:** does every `[[extension.provides]]` have a matching entry point?
- **Standard tests:** does `tests/unit_tests/test_standard.py` exist and inherit from `axiom_tests`?
- **Signed release:** will `axi ext publish` sign via Sigstore?

If any of these answers are "I'm not sure," run `axi ext lint` and follow its remediation hints. The tooling is the convention — you shouldn't need to memorize the spec.

---

## Getting Help

- Spec: [spec-aeos-0.1.md](../specs/spec-aeos-0.1.md)
- Extension self-containment: [ADR-031](../adrs/adr-031-extension-self-containment.md)
- Standards positioning: [ADR-032](../adrs/adr-032-standards-positioning-dual-track.md)
- Reference implementation: any built-in extension in `axiom/src/axiom/extensions/builtins/` after Phase 2 migration
- Discussion: project Discord / Slack (when established)
