Skip to content

Core Concepts

Every iteration follows four phases:

  1. Observe — Observers collect data: HTTP health checks, Kubernetes pod status, deployment activity, alerts. Each observer returns Observation[].
  2. Orient — Orienters analyze the observations and produce SituationAssessment objects. The framework merges these into a Situation with a summary, anomalies, correlations, priority, and confidence score.
  3. Decide — Decision strategies evaluate the situation and propose an action. Strategies declare applicableWhen predicates so only relevant strategies run. The output is a Decision with an action ID, parameters, rationale, confidence, and risk level.
  4. Act — The chosen action executes. Actions can require approval (queued for a human), run automatically, or be skipped (no-op). Each action returns an ActionResult with success/failure, duration, and optional side effects.

See The OODA Loop for the deep dive.

Plugins are the extension mechanism. A plugin can contribute components to any phase:

ComponentPhasePurpose
observersObserveCollect signals from your systems
orientersOrientAnalyze observations into assessments
decisionStrategiesDecidePropose actions based on the situation
actionsActExecute remediation or automation
endpointsAPIAdd custom REST routes

Plugins also have lifecycle hooks: onLoopStart, onObserve, onOrient, onDecide, onBeforeAct, onAfterAct, onLoopComplete.

A minimal plugin:

import { definePlugin, createObserver } from 'zupdev';
export const myPlugin = () => definePlugin({
id: 'my-plugin',
observers: {
check: createObserver({
name: 'my-check',
description: 'Check something important',
observe: async (ctx) => [{
source: 'my-plugin/check',
timestamp: new Date(),
type: 'state',
severity: 'info',
data: { status: 'ok' },
}],
}),
},
});

See Plugin Overview for the full catalog and Writing a Plugin for a step-by-step guide.

Playbooks are markdown files that get fed into the LLM during Orient and Decide. Plugins are deterministic code for execution; playbooks carry the operational knowledge — what your team learned from incident retros, system quirks, and runbooks.

playbooks/
high-error-rate.md # your team wrote this after an incident
deployment-rollback.md # when to roll back vs. debug
our-weird-legacy-api.md # tribal knowledge nobody wants to lose

Playbooks are matched against current observations (by severity, keywords, source) and appended to the investigation system prompt. Anyone can write them — it’s just markdown.

See Playbooks for the full guide.

import { createAgent } from 'zupdev';
// 1. Create -- plugins are initialized, capabilities registered
const agent = await createAgent({ name: 'my-agent', plugins: [...] });
// 2. Run -- execute a single OODA loop
const result = await agent.runLoop();
// 3. Or start continuous mode
const stop = await agent.start();
// 4. Optionally start the REST API
const server = agent.startApi({ port: 3000 });

The agent exposes these methods:

MethodDescription
runLoop()Execute one full OODA iteration. Returns LoopResult.
executeAction(id, params)Run a specific action directly, bypassing the loop.
start()Start the agent in the configured mode (manual, continuous, event-driven).
startApi(options)Start the REST API server.
getContext()Return the current AgentContext.
getCapabilities()List registered observers, orienters, strategies, and actions.
getHistory()Return past LoopResult[] from this session.
getState()Return the StateStore for reading/writing agent state.

The agent maintains a key-value StateStore used by plugins and the approval queue. State can be persisted to memory (default), a JSON file, or a SQLite database.

See State & Persistence for configuration details.

When an action’s risk is high, its confidence is below a threshold, or its autonomy mode is approval-required or human-only, the action is queued for approval instead of executing. Pending approvals can be listed, approved, or denied via the REST API.

See Approval Queue for details.

External systems can submit work items called runs via the REST API. A run flows through the OODA loop and its results are returned via polling or webhook callback.

See REST API for the runs endpoints.