Install
openclaw skills install ax-developmentAgent Experience (AX) development framework. Apply when building libraries, CLIs, APIs, or any software that will be consumed by AI agents — not just humans....
openclaw skills install ax-developmentSoftware is increasingly consumed by AI agents, not just humans. AX (Agent Experience) is the discipline of designing code, APIs, and interfaces that agents can operate reliably and autonomously.
Reject invalid inputs before expensive operations. Validate at the boundary, not deep in the call stack.
// ✅ Validate sync rules before building composite
const errors = validateSyncRules(rules, knownSources);
if (errors.length > 0) throw new AXError("INVALID_SYNC_RULES", errors);
// ❌ Discover invalid rule during HTML rendering
Same inputs → same outputs. No wall-clock dependencies, no random IDs in deterministic paths, no hidden state mutations.
// ✅ Pure function, predictable
function buildDescriptor(resources, orchestration) { ... }
// ❌ Result depends on Date.now() or Math.random() silently
When non-determinism is necessary (UUIDs, timestamps), isolate it and make it injectable.
Structured errors with codes, not just string messages. Agents parse error codes, not prose.
// ✅ Structured, parseable
{ code: "ORPHAN_SYNC_TARGET", target: "viz:render", available: ["postgres:query"] }
// ❌ Just a string
throw new Error("Target not found in resources");
No magic defaults that silently change behavior. Every configuration has a visible default. No hidden heuristics.
// ✅ Default is explicit and documented
function render(descriptor, { theme = "auto" } = {}) { ... }
// ❌ Silently detects theme from environment variable
Each function does one thing. Pipeline steps are independent and recombinable. Agents can use each step separately.
Collector → Composer → Renderer // Full pipeline
Collector → custom logic → Renderer // Agent skips composer
Minimal required inputs, maximal type safety. Accept only what you need. Return only what's useful. Avoid God objects.
// ✅ Takes exactly what it needs
function resolveSyncRules(rules: UiSyncRule[], sources: string[]): ResolvedSyncRule[]
// ❌ Takes the entire config object when it only needs two fields
function resolveSyncRules(config: FullAppConfig): ResolvedSyncRule[]
Docs live next to the code they describe. Each module has its own contract. Agents find docs by exploring the file tree, not by searching a wiki.
src/sync/
├── mod.ts # Public exports
├── resolver.ts # Implementation
├── resolver_test.ts # Tests ARE documentation
└── contract.md # I/O contract, invariants (optional, for complex modules)
Every behavior has a test. Tests are the executable specification that agents read to understand contracts. Prioritize boundary tests over happy-path.
// Test the edges, not just the middle
Deno.test("empty resources → empty descriptor", ...);
Deno.test("orphan sync target → validation error", ...);
Deno.test("broadcast rule → resolves to all-except-sender", ...);
Before shipping any module, verify:
When building CLIs that agents will invoke:
--humanSee references/cli-contracts.md for detailed patterns.
Standard error code prefixes for AX-compliant projects:
| Prefix | Domain | Example |
|---|---|---|
INVALID_* | Input validation | INVALID_SYNC_RULES |
MISSING_* | Required data absent | MISSING_RESOURCE_URI |
ORPHAN_* | Reference to non-existent entity | ORPHAN_SYNC_TARGET |
CONFLICT_* | Contradictory configuration | CONFLICT_LAYOUT_CHILDREN |
UNSUPPORTED_* | Valid but not implemented | UNSUPPORTED_LAYOUT |
Adopt this taxonomy or define your own — the point is consistency within a project.