Skip to main content

Architecture Overview

Adjutant is a persistent autonomous agent framework that runs on your local machine. It listens for messages from a messaging backend, routes them through a backend-agnostic dispatcher, and responds via LLM-powered AI (OpenCode or Claude Code CLI) or built-in commands.


High-Level Diagram

┌──────────────────────────────────────────────────────┐
│ User Device │
│ │
│ adjutant CLI ──► lifecycle modules │
│ │ │
│ ▼ │
│ Listener (telegram/listener.py) │
│ │ async polling loop │
│ ▼ │
│ dispatch.py ──► rate limit check │
│ │ authorization check │
│ ├──► /command handlers (commands.py) │
│ └──► natural language ──► chat.py │
│ │ │
│ ▼ │
│ backend.run() │
│ (OpenCode or Claude CLI) │
│ │ │
│ ▼ │
│ Adaptor send functions ──► Messaging Backend │
└──────────────────────────────────────────────────────┘

Everything runs on your machine. There is no server, no cloud component, and no data leaving your device except the messages you explicitly send and receive.


Layer Summary

LayerLocationResponsibility
CLIsrc/adjutant/cli.pyClick-based CLI — all adjutant subcommands
Common utilitiessrc/adjutant/core/Shared library: backend abstraction, paths, env, lockfiles, logging, model, platform
Messagingsrc/adjutant/messaging/Adaptor contract, dispatcher, backend implementations
Lifecyclesrc/adjutant/lifecycle/Start, stop, pause, kill, restart, update
Capabilitiessrc/adjutant/capabilities/Screenshot, vision, knowledge base, schedule, search
Identityidentity/Three-layer agent persona loaded at chat time
LLM Backendcore/backend*.pyBackend abstraction: OpenCode or Claude CLI
Agent config.opencode/, .claude/Agent definitions, workspace config, permissions, hooks

CLI Layer — src/adjutant/cli.py

The CLI is a Click application. The adjutant script in the repo root is a thin bash shim that resolves .venv/bin/python and delegates to python -m adjutant. All business logic lives in the Python modules.

Command groupModule
start / stop / restartmessaging/telegram/service.py
statusobservability/status.py
pause / resume / killlifecycle/control.py
startuplifecycle/control.py
updatelifecycle/update.py
pulse / reviewlifecycle/cron.py
kbcapabilities/kb/
schedulecapabilities/schedule/
setupsetup/wizard.py
newsnews/
screenshotcapabilities/screenshot/
searchcapabilities/search/
notify / replymessaging/telegram/notify.py, reply.py
doctor / logs / rotateobservability/, lifecycle/

Core Utilities — src/adjutant/core/

Shared library imported by every other module.

ModuleResponsibility
paths.pyResolves ADJ_DIR by walking up from the calling module until it finds .adjutant-root. Sets and exports ADJ_DIR. Provides get_adj_dir() / init_adj_dir().
env.pyExtracts credential values from .env using line-by-line parsing — never execs the file. Provides get_credential(key), has_credential(key).
lockfiles.pyManages the KILLED and PAUSED state files. Provides check functions and state mutators.
logging.pyAppends structured log lines to state/adjutant.log. Provides adj_log(component, message).
backend.pyLLM backend protocol, LLMResult, BackendCapabilities, get_backend() factory.
backend_opencode.pyOpenCode CLI backend implementation.
backend_claude_cli.pyClaude Code CLI backend implementation.
opencode.pyLow-level OpenCode CLI process management (used by backend_opencode.py).
model.pyResolves model tier names (cheap/medium/expensive) to actual model slugs from adjutant.yaml.
config.pyLoads and validates adjutant.yaml.
platform.pyOS and architecture detection.
process.pyProcess management helpers.

Capabilities Layer — src/adjutant/capabilities/

Each capability is an isolated subdirectory. Capability functions accept arguments and return a result string or raise.

CapabilityEntry ModuleDescription
kb/kb/query.py, kb/run.py, kb/manage.pyKB query, KB-local operations, KB CRUD
schedule/schedule/install.py, schedule/manage.pyScheduled job management
screenshot/screenshot/screenshot.pyPlaywright screenshot + vision caption + Telegram send
vision/vision/vision.pyLLM image analysis (OpenCode backend only)
search/search/search.pyBrave Search API integration
memory/memory/memory.py, memory/classify.pyPersistent long-term memory with auto-classification

Further Reading

  • Messaging — adaptor contract, dispatcher, Telegram internals
  • Identity & Agent — three-layer identity model, LLM backend integration
  • Backends — backend protocol, factory, capability system, error taxonomy
  • State & Lifecycle — lockfiles, state files, lifecycle state machine
  • Autonomy — pulse/review cycle, notification budget, action ledger
  • Design Decisions — why things are the way they are