Core Concepts

Monstrum Concepts and Terminology

This document defines all abstract concepts and technical terms in the Monstrum platform. It is recommended to read through this document before exploring the architecture docs or source code.


Table of Contents


Design Paradigm

From Tool to Autonomous Actor

We have always treated AI as a tool — pursuing smarter and more powerful capabilities. But in production environments, an AI Agent is no longer a passive tool; it is an independent autonomous actor: it makes decisions, invokes tools, accesses data, interacts with external systems, and even delegates tasks to other Agents.

People in society require governance — identity verification, behavioral boundaries, legal constraints, and behavioral audits. As autonomous actors in the digital world, Bots equally require a complete governance framework:

PersonBotMonstrum Implementation
ID cardIdentityBot ID + Name + Description + Workspace
Legal constraintsPermission policiesRolePermissions (allowed operations + parameter scopes)
Work authorizationResource bindingBotResource (which systems to bind, which identity to use)
Keys / passwordsCredentialsCredential (encrypted storage, Bot never sees plaintext)
Salary budgetToken budgetmonthly_token_budget + cost tracking
Behavioral recordsAudit logsActionLog (full chain, tamper-proof)
Experience / memoryBot memoryMemoryEntry (partitioned storage, automatic extraction)

This is not an analogy — this is Monstrum’s core design paradigm. A Bot is a governed autonomous actor, not an LLM wrapper.

Platform-Enforced, Not AI Self-Discipline

AI Agents are capable but untrustworthy — they hallucinate, can be injected, and may exceed their authority. You cannot rely on AI self-discipline for security.

Monstrum’s core thesis: Security is guaranteed by platform architecture, not by relying on AI’s self-restraint.

  • LLM says “I won’t access that repository”? → Not enough. The platform makes it so the Bot cannot even see the tools for that repository
  • LLM says “I won’t leak the API Key”? → Not enough. The platform never gives plaintext credentials to the LLM
  • LLM says “I’ll only operate within authorized scope”? → Not enough. The platform validates parameters against boundaries after every tool call

Three governance principles are derived from this thesis:

Three Governance Principles

1. Least Privilege — Invisible = Non-existent

A Bot can only see tools that have been explicitly authorized. Unbound Resources are completely invisible to the Bot — not “visible but forbidden to call,” but the LLM simply does not know they exist. This is more thorough than traditional RBAC’s “access denied”: the attack surface shrinks from “attempting to exceed authority” to zero.

2. Credential Isolation — LLM Never Touches Secrets

Credentials are stored encrypted. At execution time, the platform decrypts and injects them into the Executor layer; the LLM never has access to any plaintext throughout its entire lifecycle. Even if the LLM is attacked via prompt injection, it cannot leak credentials.

3. Fail-Closed — Errors Mean Stop

When any component fails, the result is “the Bot can do nothing,” rather than “unrestricted access”:

  • ToolResolver fails → returns empty tool list (Bot has no tools available)
  • Guardian fails → request denied
  • EventDispatcher pre-delivery re-check fails → delivery blocked

Permission Design: Declarative + Two-Layer Filtering + Delegation Without Escalation

Declarative over imperative. Plugin developers don’t need to write permission-checking code — they just declare “which parameters to check and how to match”:

ScopeDimension:
  key: repos           →  "check the repos parameter"
  param_paths: [repo]  →  "extract value from the repo field in tool parameters"
  match_mode: pattern  →  "match using fnmatch"

Platform automatically: extract parameters → match scope_constraints → allow/deny

Two independent filtering layers. Either layer alone is sufficient to prevent privilege escalation. Even if one layer is bypassed, the other still takes effect:

  Pre-LLM (ToolResolver)              Post-LLM (Guardian)
┌───────────────────────────┐    ┌───────────────────────────┐
│ Filter tool visibility     │    │ Validate call parameters   │
│ No binding = LLM can't see │ →  │ Parameter out of scope =   │
│ Error → return empty list  │    │   deny execution           │
└───────────────────────────┘    │ Error → deny request       │
                                  └───────────────────────────┘

Delegation without escalation. When Bot A delegates a task to Bot B, Bot B’s effective permissions are the intersection of Bot A’s delegation constraints and Bot B’s own permissions — they can never exceed either party. This prevents Confused Deputy attacks.

Philosophy of Two Tool Categories

A Bot’s tools are divided into two categories with fundamentally different governance strategies:

External Resource ToolsBot Self-Owned Capability Tools
EssenceBot accesses external systems on behalf of usersBot operates on its own data
AnalogyAn employee accessing GitHub with a company accountAn employee writing memos in their own notebook
Governance needsFull permission chain (Guardian validation)Ownership naturally guarantees access; does not go through Guardian
ExamplesSSH, MCP, GitHubMemory, Scheduling, Workflows, Progress reporting

The criterion for this distinction is simple: Who owns the data? Operating on the Bot’s own data → self-owned capability; operating on external systems or other Bots → external resource.


Core Concept Distinctions

There are several groups of easily confused concepts in Monstrum that need to be clearly distinguished.

Bot vs Agent vs LLM

ConceptWhat is itEntity in Monstrum
LLMLarge Language Model, a pure reasoning engine. Receives prompts and tool definitions, returns text or tool calls. Does not execute any operations itself.LLMProvider (API configuration), ModelInfo (model metadata). The LLM is the Bot’s “brain,” but is not equivalent to the Bot.
BotA governed AI entity on the Monstrum platform. Has identity (name, description), permissions (BotResource bindings), configuration (BotRuntimeConfig), memory, and budget. The object of platform-enforced governance.Bot model. One Bot = one LLM configuration + a set of resource bindings + permission policies + runtime state. A Bot is not directly equivalent to an LLM — it is the “shell” for the LLM, giving the LLM identity, tools, and constraints.
AgentAn AI program with autonomous decision-making capabilities. Has two meanings in Monstrum (see below).Depends on context.

Two Meanings of “Agent”

In the Monstrum codebase, the word “Agent” appears in two different contexts:

ContextMeaningCode LocationDescription
AgentRuntimeThe Bot’s LLM execution engine — responsible for the LLM call loop (reasoning → tool call → result → continue)services/runner/agent/runtime.pyThis is “Agent” as a design pattern: an LLM program that can autonomously loop through tool calls. Every Bot executes tasks through AgentRuntime.
Monstrum Agent (type_id=monstrum-agent)An independent entity for external AI Agents connecting to the platform via WebSocketservices/core/api/agents.py, agent_ws/Here “Agent” refers to an external AI program that connects to the platform via WebSocket and registers tools. Agent is an independent platform entity (AgentTable), authenticated via agent_key, not managed as a Resource. ResourceType monstrum-agent is used for the Agent’s own capability declarations.

Summary:

  • LLM = reasoning engine (calls API, returns text/tool calls)
  • Bot = platform-governed AI entity (LLM + permissions + tools + memory + budget)
  • AgentRuntime = the Bot’s internal execution loop (the code that “lets the LLM autonomously loop through tool calls”)
  • Monstrum Agent = an external AI program that connects to the platform via WebSocket as an independent entity (AgentTable, authenticated via agent_key, with its own tool registration and management API)

Session vs Task

Two Bot execution modes:

SessionTask
TriggerUser sends an IM messageAPI call / Scheduled trigger / Bot-to-Bot delegation / Event trigger
InteractionMulti-turn conversation with contextSingle execution, independent context
LifecycleRecycled after 30 minutes of inactivityEnds upon completion
MemoryMemoryContext (three-layer cache, scope-partitioned)AgentRuntime loads global + task memory
PersistenceOptional (/chathis toggle)Checkpoint-recoverable

Executor vs Plugin

ExecutorPlugin
EssenceCode implementation of tool executionA complete integration package (declaration + implementation)
ContainsA single ExecutorBase subclassmonstrum.yaml (declaration) + executor.py (Executor)
RegistrationExecutorRegistryPluginManager (auto-scan + register Executor)

In other words: Plugin = ResourceType declaration + Executor implementation. Built-in types also have Executors, but they are not loaded through the Plugin mechanism.


Resource Model

Monstrum’s resource management is a three-layer abstraction: Declare capabilities → Instantiate connections → Authorize bindings.

ResourceType

Capability declaration. Defines what an integration “can do.”

FieldDescription
idUnique identifier (e.g., ssh, mcp, github)
nameDisplay name
tools: ToolDef[]Tool definitions callable by the LLM
scope_dimensions: ScopeDimension[]Parameter-level permission check rules
auth_methods: AuthMethodDef[]Supported credential acquisition methods
credential_schema: FieldDef[]Credential field definitions (frontend auto-renders forms)
config_schema: FieldDef[]Connection configuration field definitions
tool_discoveryTool discovery mode: static / dynamic / configured
builtinWhether built-in (cannot be deleted)

Built-in types (6):

type_idDisplay NameTool DiscoveryDescription
sshSSHstaticRemote command execution, asyncssh
mcpMCPdynamicModel Context Protocol tool server (Streamable HTTP)
botBotstaticBot-to-Bot task delegation
webWebconfiguredMulti-engine search + HTTP fetching
monstrum-agentMonstrum AgentdynamicExternal Agent WebSocket connection, Agent’s own capability declarations
web3Web3 (EVM)staticEVM chain operations (balance, transfer, contract calls, events, gas estimation)

MCP vs Monstrum Agent

Two dynamic tool discovery mechanisms with different directions and architectures:

MCPMonstrum Agent
DirectionPlatform connects to tool serverExternal Agent connects to platform
TransportStreamable HTTPWebSocket (/ws/agent)
AuthenticationOAuth 2.1 / Noneagent_key (Agent independent entity authentication)
Tool registrationPlatform actively discoversAgent actively registers (grouped by group, source=agent/mcp/plugin)
type_idmcpmonstrum-agent
Display nameMCPMonstrum Agent
Entity modelResource (ResourceType instance)Independent entity (AgentTable), not managed as Resource
Management APIResource CRUDDedicated API at services/core/api/agents.py

Monstrum Agent key components:

  • AgentConnectionManager — Connection management (indexed by agent_id), authentication, tool registration
  • ToolCatalog — Dynamic tool storage (source distinguishes agent/mcp/plugin)
  • ToolExecutor._try_execute_via_agent() — Forward tool calls via WebSocket (replaces the deleted AgentExecutor)

Resource (Resource Instance)

A concrete external system connection. A single ResourceType can have multiple Resource instances.

FieldDescription
idUUID
workspace_idOwning workspace
type_idCorresponding ResourceType
nameUser-defined name (e.g., “Production Server”)
configConnection configuration (JSON, schema defined by ResourceType)
statusCONNECTED / DISCONNECTED / AUTH_EXPIRED / AUTH_REQUIRED

ResourceCredential

Encrypted authentication information. The LLM can never access plaintext.

FieldDescription
idUUID
resource_idOwning Resource
auth_methodAuthentication method (oauth2_auth_code / api_key / token / ssh_key / basic)
encrypted_fieldsEncrypted credential values (visible only at DB layer)
display_fieldsNon-sensitive fields (displayable in frontend)
auto_refreshWhether auto-refresh is supported (OAuth Token)
discovered_toolsDynamically discovered tool definitions (MCP / Monstrum Agent only)
discovery_statusTool discovery status: success / error / pending

BotResource (Resource Binding)

The authorization relationship between a Bot and a Resource. This is the core carrier of permissions.

FieldDescription
idBinding ID
bot_idAuthorized Bot
resource_idBound Resource
credential_idWhich credential to use
permissionsRolePermissions — permissions effective at runtime (see below)
is_activeWhether enabled

Tool Discovery Modes (ToolDiscovery)

The tool_discovery field of ResourceType determines how tools are discovered:

ModeDescriptionRepresentative Types
staticTool definitions are declared in the ResourceType, do not changeSSH, Bot, Web3
dynamicTools are discovered at runtime (auto-detected after connection), persisted to ResourceCredentialMCP, Monstrum Agent
configuredTool definitions are fixed, but behavior is determined by config_schema configurationWeb (search engine selectable)

Permission Model

Two independent security filtering layers, either of which alone is sufficient to prevent privilege escalation.

RolePermissions (Runtime Permissions)

Flat permissions directly attached to BotResource, serving as the sole data source for runtime validation.

FieldDescription
allowed_operationsOperation glob list (e.g., ["issue.*", "pr.read"])
allowed_toolsTool glob list (for dynamic types, e.g., ["get_menu", "list_*"])
scope_constraintsParameter-level constraints (e.g., {"repos": ["org/repo-*"]})
delegateDelegation constraints DelegateConstraints (see below)

ScopeDimension (Permission Dimension Declaration)

Declarative rules — plugin developers only need to declare “what to check,” and the platform automatically enforces it.

FieldDescription
keyThe key in the scope dictionary (e.g., repos, hosts, commands)
param_pathsJSON paths to extract values from tool parameters (tried in order)
match_modeMatching method: pattern (fnmatch) / path (glob) / exact
error_templateError message template when denied ({value} placeholder)

DelegateConstraints (Delegation Constraints)

Constrains the effective permissions of the called Bot during Bot-to-Bot calls. Prevents Confused Deputy attacks.

FieldDescription
allowed_toolsTools visible to the called Bot (glob, Pre-LLM filtering)
scope_constraintsIntersected with the called Bot’s own scope (Post-LLM validation)

Role (Role Template)

RBAC role with preset permission combinations. Can be assigned to Bots, supports inheritance.

FieldDescription
idUUID
nameRole name (unique within workspace)
parent_role_idInherits from parent role
permissionsRolePermissionConfig — hierarchical permission configuration

Two-Layer Filtering Mechanism

Pre-LLM: ToolResolver
  Input: BotResource binding list
  Output: Tool list visible to the LLM (ToolResolution)
  Principle: No binding = no tools; LLM is completely unaware of unauthorized tools
  On error: Returns empty list (Fail-closed)

Post-LLM: Guardian
  Input: LLM-returned tool call + parameters
  Output: Allow/Deny (BotResourcePermissionResponse)
  Principle: Validates parameter legality according to ScopeDimension declarations
  On error: Deny request (Fail-closed)

Tool System

ToolDef (Tool Definition)

An LLM-callable tool declaration, defined in ResourceType.

FieldDescription
nameTool name (e.g., github_list_issues)
descriptionDescription visible to the LLM
operationAssociated operation (e.g., issue.read)
input_schemaJSON Schema parameter definition

ToolCatalog (Tool Directory)

A data-driven global tool index. Loads all ResourceType tool definitions from the DB at startup.

DataDescription
_tool_maptool_name → (type_id, operation)
_type_toolstype_id → [tool_names]
_scope_dimstype_id → [ScopeDimension]
_dynamic_toolsresource_id → [ToolDef] (dynamically discovered tools)

ToolResolution (Tool Resolution Result)

The output of ToolResolver. Contains the tool list visible to the LLM and internal routing information.

FieldDescription
toolsLLM tool definition list (may have qualified name prefix)
_resource_mapqualified_name → resource_id
_binding_mapqualified_name → binding_id
_name_mapqualified_name → original_tool_name
resource_groupsTool summary grouped by Resource (injected into system prompt)

Qualified name rules:

  • Single binding: tool name unchanged (github_list_issues)
  • Multiple bindings of same type: {resource_name}__{tool_name} (Work__github_list_issues)

Two Tool Categories

External Resource ToolsBot Self-Owned Capability Tools
EssenceBot accesses external systemsBot operates on its own data
ExamplesSSH / MCP / GitHubMemory, Scheduling, Workflows, Progress
Pre-LLMBotResource binding filteringBotRuntimeConfig toggle / always injected
Post-LLMGuardian scope validationDoes not go through Guardian (ownership naturally guarantees access)
Requires ResourceYesNo

Bot Self Sentinel (Bot Self-Owned Tool Sentinel)

Bot self-owned tools use a special prefix for routing, bypassing Guardian:

Format: __bot__:{capability}:{operation}
Example: __bot__:memory:write, __bot__:schedule:create

ToolResolver → returns sentinel name
AgentRuntime → detects __bot__ prefix → calls bot_self_tools.py handler
ToolControl Switch
memory_write / memory_deleteAlways injected
memory_load_context / memory_unload_contextAlways injected
task_progressAlways injected
schedule_create / schedule_list / schedule_deleteBotRuntimeConfig.self_schedule
send_to_channelBotRuntimeConfig.self_channel

Execution Architecture

AgentRuntime (Agent Execution Engine)

The core LLM call loop. Receives tasks, builds system prompts, and loops through LLM and tool calls until completion.

Responsibilities:

  1. Build system prompt (base template + memory + Agent Mode + Skills)
  2. Call ToolResolver to filter the tool list (Pre-LLM)
  3. Call LLM → get tool calls or text response
  4. Call ToolExecutor to execute tools (including Guardian Post-LLM validation)
  5. Loop until the LLM returns a final text response, reaches max_iterations, or times out
  6. Trigger memory extraction after task completion

Agent Mode (Reasoning Mode):

ModeBehavior
reactiveExecute directly without outputting a plan (default)
planningOutput a numbered plan first, then execute step by step
adaptivePlan → Execute → Reflect → Adjust plan

ToolExecutor

The middle layer that orchestrates Guardian validation + Executor execution + audit logging.

Execution flow:

1. Guardian.check_bot_resource_permission() → permission check + credential decryption
2. ExecutorRegistry.execute_tool() → route to the specific Executor
3. DelegateConstraints secondary validation (if delegation is involved)
4. AuditorClient.log() → record operation log
5. EventBus.publish() → publish RunnerEvent

Note: Sentinel routing (__bot__:* and workflow tools) is handled upstream in AgentRuntime / SessionManager, which directly calls bot_self_tools or workflow_tools without going through ToolExecutor. ToolExecutor only handles external resource tools.

ExecutorBase (Executor Base Class)

The abstract base class for all Executors.

Property/MethodDescription
resource_typeThe resource type handled (e.g., ssh)
supported_operationsList of supported operations
execute(request)Execute a tool call → ExecuteResult
_get_token(request, field)Unified credential value retrieval
get_sdk_functions()Returns Platform SDK functions

ExecuteRequest (Execution Request)

The complete context passed to an Executor.

FieldDescription
bot_id / task_idCaller identifier
operationOperation name
paramsTool parameters
tool_nameOriginal tool name (used for routing when multiple tools share the same operation)
credential_fieldsCredentials decrypted by Guardian
resource_configResource connection configuration
resource_idResource ID (used for dynamic type routing)
delegateDelegation constraints
credential_refreshAsync refresh callback on 401

ExecuteResult (Execution Result)

FieldDescription
successWhether successful
dataReturn data
errorError message
statusSUCCESS / ERROR / SCOPE_VIOLATION

ExecutorRegistry (Executor Registry)

A global singleton that manages all Executor instances. Routes tool calls to the corresponding Executor by type_id.

RunnerState (Runner Global State)

A service-level singleton that holds references to all runtime components.

FieldDescription
llm_providerDefault LLM Provider
core_client / guardian_client / auditor_clientInter-service clients
session_managerSession manager
event_dispatcherEvent dispatcher
agent_connection_managerAgent WebSocket connection manager
adapter_managerGateway adapter manager (cross-service message delivery)
workspace_promptsWorkspace-level prompt cache
active_tasksRunning async tasks (execution_id → asyncio.Task)
active_executorsRunning workflow executors (execution_id → WorkflowExecutor)

Guardian / PolicyDecisionPoint (Permission Decision Engine)

Post-LLM parameter-level permission validation.

Two-level authorization:

  1. Coarse-grained (can_access()): Is the operation in allowed_operations?
  2. Fine-grained (authorize()): Do the parameters conform to scope_constraints?

Scope Checker: Built-in checkers (github, gitlab, ssh, web, bot, gmail, notion, monstrum-agent, etc.) + declarative generic checker (check_scope_declarative()).


Sessions and Messages

Session

An active conversation between a user and a Bot.

FieldDescription
idSession UUID
sourceChannel type (web / slack / feishu / discord / telegram / webhook)
channel_idChannel or user ID
bot_idThe Bot in conversation
chat_typeprivate (direct message) / group (group chat)
config_idGateway configuration ID (for precise routing)

Session Key: (config_id|source, channel_id, bot_id) — config_id takes priority (the same Bot can be bound to multiple Gateways).

Lifecycle:

  1. First message → Create Session (load persisted history)
  2. Each message → SessionWorker FIFO processing
  3. 30 minutes idle → Trigger memory extraction → Save session → Recycle Session

MessageEnvelope

Unified internal message format. All external channel messages are first converted to Envelopes before processing.

FieldDescription
idMessage UUID
channel_typeChannel type
channel_idChannel ID
bot_idTarget Bot
sender_id / sender_nameSender identifier and display name
contentMessage content
chat_typeprivate / group
config_idGateway configuration ID
workspace_idWorkspace

SessionWorker (Session Worker Coroutine)

One background coroutine per Session, processing messages sequentially via a FIFO queue. Responsible for calling AgentRuntime and delivering responses.

ResponseDelivery

Exponential backoff retry mechanism for delivering responses back to external channels (via Gateway adapters).

MessageDeduplicator

Sliding window deduplication to prevent duplicate messages caused by Gateway webhook retries.

Session Persistence

Channel-level conversation persistence (toggled by administrators via the /chathis command).

ConceptDescription
ChannelConversationDB table, unique constraint on (config_id, channel_id, bot_id)
Save timingWhen Session expires
Load timingWhen Session is created
Compression thresholdTriggered at 80 messages
Compression strategyLLM summarizes old messages → keep latest 50 messages + summary

Memory System

MemoryEntry (Memory Entry)

A single memory entry.

FieldDescription
idUUID
categorypreference / rule / event / knowledge
contentMemory content
sourceuser (manual) / auto (LLM-extracted) / system (system-generated)
importanceImportance score from 1-10
originSource scope (see below)

Origin (Memory Scope)

Memories are managed by partition based on the origin field, which determines in what context the memory is visible.

origin valueMeaningVisible scope
NULLGlobal memoryAll contexts
channel:{config_id}:{channel_id}Channel memorySessions in that IM channel
task:{task_id}Task memoryDuring that task’s execution
resource:{resource_id}Resource memoryContexts where that Resource is bound
schedule:{schedule_id}Schedule memoryWhen that scheduled task fires
workflow:{workflow_id}Workflow memoryWhen that workflow executes

MemoryContext

Three-layer memory cache in Session mode.

LayerContentLoad timing
_baseGlobal + current scope memoriesWhen Session is created
_resourceMemories related to bound ResourcesAfter ToolResolver completes
_injectedDynamically loaded cross-scope read-only memoriesWhen Bot calls memory_load_context

Key mechanisms:

  • invalidate() — marks base as needing reload after memory_write
  • inject(scope) / unload(scope) — load/unload cross-scope memories at runtime
  • get_all() — merges all three layers, sorted by importance descending

MemoryExtractor

LLM-driven automatic memory extraction.

Trigger timing: Task completion / Session expiration (when auto_memory is enabled)

Process:

  1. Format conversation history
  2. Inject current memories as reference
  3. LLM analysis → output JSON (category + content + importance)
  4. Atomically replace source=auto memory entries (delete all then insert)

Prompt Management

Prompt Key

9 centrally managed prompts, defined in services/runner/prompts.py.

KeyPurposeSupported Variables
default_task_systemTask mode system prompt{bot_name}, {bot_description}
default_session_systemSession mode system prompt{bot_name}, {bot_description}
group_chatGroup chat supplementary prompt
planningPlanning reasoning mode instructions
adaptiveAdaptive reasoning mode instructions
memory_extractionMemory extraction prompt{current_section}, {conversation}
memory_extraction_systemMemory extraction system role
conversation_summaryConversation compression prompt{conversation_text}
conversation_summary_systemConversation compression system role

Three-Layer Resolution

Priority: Bot-level (runtime_config.prompts) > Workspace-level (DB table) > Code default (PROMPT_DEFAULTS)

get_prompt(bot_config, key, workspace_prompts=...) → str

System Prompt Assembly Order

Session mode (SessionManager) and Task mode (AgentRuntime) have different assembly paths:

Session mode:

1. Bot.system_prompt (identity description) or default_session_system template
2. group_chat supplementary prompt (only in group chat)
3. ## Available Resources (resource group summary from ToolResolver output)
4. ## Bot Memories (MemoryContext formatted by scope partition)
5. Skill instructions (Markdown content loaded from DB)

Task mode:

1. Bot.system_prompt (identity description) or default_task_system template
2. ## Available Resources (resource group summary from ToolResolver output)
3. ## Bot Memories (global + task + resource memories)
4. Agent Mode instructions (planning / adaptive, if configured)
5. Skill instructions

Difference: The group_chat prompt is only injected in group chat scenarios in Session mode; Agent Mode instructions (planning/adaptive) are only injected in Task mode.

PromptEngine (7-Layer Assembly Engine)

services/runner/prompt_engine.py — A structured prompt assembler replacing simple string concatenation.

7 layers (in priority order):

LayerDescription
PlatformPlatform base system instructions
WorkspaceWorkspace-level prompt templates (DB)
IdentityBot custom system_prompt / description
SceneScene instructions (group chat / task mode, etc.)
Resources## Available Resources resource group summary
SkillsSkill instructions (enabled Skills)
Memories## Bot Memories, with recency decay scoring and token budget eviction

Event System

PlatformEvent

Events covering the full lifecycle.

FieldDescription
event_typeEvent type (e.g., task.completed, schedule.fired)
source_typeSource type: task / workflow / schedule / session / bot
source_idSource ID
workspace_idWorkspace
dataEvent payload

Event type categories:

PrefixSourceExamples
task.*AgentRuntimetask.completed, task.failed
workflow.*WorkflowExecutorworkflow.completed, workflow.failed
schedule.*SchedulerServiceschedule.fired
session.*SessionManagersession.created, session.expired
runner.*ToolExecutorrunner.github.issue.created (see RunnerEvent format explanation below)
custom.*Bot (emit_event)User-defined

RunnerEvent (Execution Event)

Fine-grained events published after tool execution.

FieldDescription
capabilityResource type (e.g., github)
operationOperation name (e.g., issue.create)
resultSUCCESS / FAILURE / ERROR / DENIED
event_typeAuto-generated (see below)

event_type generation rules: runner.{capability}.{transformed_operation}

The last segment of the operation is transformed based on the result (not simply appending the result):

  • issue.create + SUCCESS → issue.created → event_type = runner.github.issue.created
  • issue.create + FAILURE → issue.create_failed → event_type = runner.github.issue.create_failed
  • exec.run + SUCCESS → exec.ran → event_type = runner.ssh.exec.ran

EventSubscription

A subscription created by a Bot via the subscribe_event tool.

FieldDescription
patternfnmatch matching pattern (e.g., task.*, schedule.fired)
bot_idSubscriber Bot
instructionInstruction injected when the event fires
target_typeDelivery target: bot (default) / workflow
workflow_idTarget workflow (when target_type=workflow)

EventDispatcher

The event routing bridge. Listens to EventBus, matches subscriptions, and delivers to targets.

Delivery strategy:

  • Bot target: Preferentially inject into active Session → if no Session, create a Task
  • Workflow target: Directly trigger workflow execution

Security mechanism: Re-checks binding permissions before delivery (bindings may have been revoked after subscription creation).

WorkflowTrigger

A persisted event→workflow mapping (stored in DB, loaded at startup).

FieldDescription
event_patternfnmatch pattern
workflow_idTarget workflow
instructionInstruction passed to the workflow

EventBus

Publish/subscribe bus. Supports both RunnerEvent and PlatformEvent payloads.


Workflows

Workflow (Workflow Definition)

A visual DAG workflow.

FieldDescription
idUUID
nameWorkflow name
bot_idOwning Bot
statusDRAFT / ACTIVE / DISABLED
stepsStep list (Step[])
edgesEdge list (Edge[])

Step (Workflow Step)

FieldDescription
idUUID
typeStep type (see below)
configStep configuration (varies by type)
input_mappingVariable mapping (e.g., {{step1.output.field}})
timeout_secondsStep timeout
max_retriesMaximum retry count

StepType (Step Types):

TypeDescription
STARTEntry node
ENDExit node
RESOURCE_CALLCall a resource tool
CONDITIONConditional branch (AST safe expression evaluation)
PARALLELParallel branches (fail-fast by default)
WAITDelay wait
APPROVALManual approval (pauses execution, awaits approval)
LLM_CALLSingle LLM call
FOR_EACHLoop iteration
SUB_WORKFLOWSub-workflow
SCRIPTScript execution (future extension)

Edge (Connection)

A directed connection between steps.

FieldDescription
source_step_idSource step
target_step_idTarget step
conditionCondition expression (used for conditional branches)

WorkflowExecution

FieldDescription
idExecution ID
workflow_idWorkflow ID
statusPENDING / RUNNING / SUCCESS / FAILED / CANCELLED / TIMEOUT / WAITING_APPROVAL
triggered_bymanual / schedule / trigger / api

WorkflowExecutor

Safety mechanisms:

  • DAG cycle detection: DFS three-color marking
  • Timeout budget: min(global deadline, step timeout)
  • Parallel Fail-Fast: asyncio.wait(FIRST_EXCEPTION) + cancel sibling branches
  • Safe expressions: AST whitelist visitor (forbids eval())
  • Variable pipeline: Inter-step variable passing, ast.literal_eval for value parsing

Trigger methods:

MethodEntry Point
API direct triggerPOST /workflows/{id}/execute
Scheduled triggerSchedule.config target_type: "workflow"
Event triggerWorkflowTrigger + EventDispatcher

Tasks and Scheduling

Task

An asynchronous work unit assigned to a Bot for execution.

FieldDescription
idUUID
bot_idExecuting Bot
instructionTask instruction
statusPENDING / RUNNING / COMPLETED / FAILED / CANCELLED
constraintsExecution constraints (TaskConstraints)
outputTask result
token_usageToken consumption (TokenUsage)
parent_task_idParent task (Bot-to-Bot delegation chain)
call_depthCall depth
checkpointCheckpoint state (recoverable)
progressProgress {percentage, message}

TaskConstraints

FieldDescription
max_tokensToken limit
timeoutTimeout in seconds
allowed_toolsTool whitelist

Schedule (Scheduled Task)

Cron-driven scheduled tasks.

FieldDescription
bot_idExecuting Bot
cron_exprCron expression
timezoneTimezone
input_templateTask template when triggered
configJSON configuration dictionary
target_type@property, reads config["target_type"], defaults to task, optionally workflow
workflow_id@property, reads config["workflow_id"] (when type is workflow)

Plugin System

PluginManifest (Plugin Manifest)

The complete declaration of a plugin. A single monstrum.yaml file defines everything.

FieldDescription
idPlugin ID
name / versionName and version
resource_typeResourceType declaration (tools, permissions, credentials, configuration)
executorExecutor module/class reference
dependenciesPython dependencies

PluginManager

Orchestrates the complete plugin lifecycle: scan plugins/ → parse Manifest → persist ResourceType to DB → load/register Executor → reload ToolCatalog.

PluginLoader

Dynamically loads Executor classes via importlib. Supports auto-discovery (the sole ExecutorBase subclass in the directory) and explicit specification (module + class_name).

Built-in vs Plugin

Built-inPlugin
Locationservices/runner/executors/plugins/{name}/
LoadingHard-coded registration at platform startupPluginManager auto-discovery
builtinTrueFalse
DeletableNoYes
Declarationbuiltin_resource_types.pymonstrum.yaml

SDK

The monstrum_sdk/ package provides two paths for accessing platform capabilities.

PluginClient

Tool-level calls that go through the full Guardian permission chain. Suitable for Skills, Workflow steps, and cross-plugin composition.

client = get_plugin_client("github", bot_id, task_id)
await client.list_issues(repo="org/repo")  # Auto-builds tool_name, goes through Guardian

Platform SDK

Direct access to built-in Executor capabilities, bypassing Guardian. Suitable for trusted code within the platform.

from monstrum_sdk import platform
await platform.ssh.run(host="dev-1", command="uptime", credential="key-1")
await platform.mcp.call_tool(tool="get_menu", params={...})
await platform.bot.execute_task(bot_id="b1", instruction="...")
await platform.events.emit(name="custom.deploy", data={...})

Namespaces: ssh, mcp, bot, web, web3, oauth, events

HttpExecutorBase (HTTP Executor Base Class)

A common base class for HTTP API plugins.

FeatureDescription
_http_get/post/patch/deleteStandard HTTP methods
_build_auth_headersAutomatically build authentication headers
401 auto-refreshcredential_refresh callback
_paginate()Link header pagination

PluginClient vs Platform SDK

PluginClientPlatform SDK
Permission checkFull Guardian chainNone (caller is responsible)
Use caseSkills / Workflow / cross-pluginTrusted code within the platform
Credential sourceDecrypted and injected by GuardianExplicitly passed by caller
Audit loggingAutomatically recordedNot recorded

Gateways and Adapters

GatewayConfig (Gateway Configuration)

Configuration for connecting an external channel.

FieldDescription
idConfiguration ID (i.e., config_id)
source_typeChannel type (slack / feishu / telegram / discord / webhook / webchat)
bot_idBot to route to
configChannel-specific configuration (API Token, Webhook URL, etc.)

Adapter

Channel protocol adapter. Responsible for receiving external messages → converting to MessageEnvelope → delivering responses.

Built-in adapters: Slack, Feishu, Telegram, Discord, Webhook, Web Chat

AdapterManager

Adapter lifecycle management. Supports registration/deregistration/lookup of adapters by config_id. Injected cross-service into RunnerState for use by features like send_to_channel.


Users and Multi-Tenancy

User

Platform user account.

FieldDescription
idUUID
email / usernameLogin credentials
display_nameDisplay name
localeLanguage preference

Workspace

Tenant isolation space. All entities (Bots, Resources, audit logs) are isolated by Workspace.

FieldDescription
idUUID
name / slugName and URL identifier
settingsConfiguration (default LLM model, Token budget, etc.)

WorkspaceMember

RolePermissions
OWNERHighest privileges
ADMINAdministrative privileges
MEMBERStandard member
VIEWERRead-only

BotGroup

Logical grouping of Bots. A Workspace can have multiple BotGroups, and each Bot can belong to multiple Groups.

FieldDescription
idUUID
workspace_idOwning workspace
nameGroup name (unique within workspace)
descriptionDescription
iconDisplay icon

Tenant Isolation (TenantContext)

Multi-tenant data isolation mechanism with dual guarantees at both the application layer and database layer.

ComponentDescription
TenantContextcontextvars.ContextVar, async-safe workspace context
PostgreSQL RLSRow-Level Security policies enabled on core tables
TenantCacheThread-safe in-memory cache with per-tenant isolated namespaces
TenantLogFilterLog filter that automatically injects tenant_id
create_tenant_task()Propagates tenant context across asyncio.create_task() boundaries

Audit and Cost

ActionLog (Operation Log)

Full-chain audit entries.

FieldDescription
task_id / bot_idAssociated entities
operationOperation type (see below)
resultResult summary
action_detailFull details (JSON)
permission_grantedWhether permission was granted
prompt_tokens / completion_tokensToken consumption (for LLM requests)
modelModel used
duration_msExecution duration
execution_locationExecution location: "cloud" / "agent:{name}" (Agent routing audit)

OperationType (Operation Types):

TypeDescription
TOOL_CALLTool call
LLM_REQUESTLLM request
PERMISSION_CHECKPermission check
TASK_START / TASK_COMPLETE / TASK_FAILTask lifecycle
CREDENTIAL_ACCESSCredential access
SCHEDULE_TRIGGERED / SCHEDULE_COMPLETED / SCHEDULE_FAILEDSchedule lifecycle

TokenStatistics

FieldDescription
total_prompt / total_completionCumulative tokens
total_tasksTotal tasks
estimated_cost_usdEstimated cost
budget_remainingRemaining budget
is_budget_exceededWhether budget is exceeded

Budget Enforcement

monthly_token_budget (BotRuntimeConfig) → accumulates after each LLM request → automatically terminates execution when budget is exceeded.


LLM Provider

LLMProvider

LLM API integration configuration.

FieldDescription
idUUID
provider_typeProvider type (see below)
base_urlCustom API endpoint
modelsAvailable model list (ModelInfo[])
default_modelDefault model
is_defaultWhether this is the workspace default
encrypted_api_keyEncrypted API Key

Supported Provider types:

  • International: ANTHROPIC, OPENAI, GEMINI, MISTRAL
  • China domestic: DEEPSEEK, QWEN, KIMI, GLM, DOUBAO, HUNYUAN, ERNIE
  • Local: OLLAMA, VLLM, LMSTUDIO
  • Custom: CUSTOM_OPENAI (any service compatible with the OpenAI API)

ModelInfo (Model Information)

FieldDescription
idModel identifier (e.g., claude-sonnet-4-5-20250929)
input_priceInput price (USD/million tokens)
output_priceOutput price (USD/million tokens)
context_windowContext window size

Design Principles Quick Reference

For detailed discussion, see the Design Paradigm section.

PrincipleOne-liner
Bot is an autonomous actorNot an LLM wrapper, but the governance shell the platform puts around the LLM (identity + permissions + credentials + memory + budget + audit)
Platform-enforced, not AI self-disciplineSecurity is guaranteed by architecture, not by relying on LLM self-restraint
Least privilegeInvisible = non-existent. Unauthorized tools are completely invisible to the LLM
Credential isolationLLM never touches plaintext credentials; injection happens at the execution layer
Fail-ClosedAny component failure → Bot can do nothing, rather than being unrestricted
Declarative permissionsPlugins declare ScopeDimension, the platform’s universal engine checks automatically
Two independent filtering layersPre-LLM (visibility) + Post-LLM (parameter validation); either layer alone is sufficient to prevent escalation
Delegation without escalationBot-to-Bot calls: child Bot effective permissions = delegation constraints ∩ own permissions
Bot self-owned vs external resourceOperating on own data does not go through Guardian; operating on external systems goes through the full permission chain
Workspace isolationAll entities are isolated by workspace; event delivery checks consistency
Single process, splittableRuns merged, but maintains Local Client abstraction for future microservice decomposition