Core Concepts
Polyant is an open-source platform for building, deploying, and operating AI assistants at scale. A single installation can host many independent agents — each one a configured assistant with its own personality, tools, memory, and connected channels.
The platform is built around three goals:
- Configuration over code. Operators shape an agent’s behavior from a web admin panel, not by editing source files. Prompts, skill enablement, channel credentials, and secrets are all stored in PostgreSQL and editable at runtime.
- Multi-channel by design. The same agent can answer in Telegram, Slack, WhatsApp, and through an OpenAI-compatible HTTP API — without code changes.
- Observability built in. Every message and every tool call is logged. Audit logs and analytics ship with the platform.
This page is a landing — a fast tour of the vocabulary and the moving parts. Each concept links forward to its dedicated chapter.
Agent
An agent is an agent identity whose configuration — prompts, enabled tools, skills, channels, secrets — is stored in PostgreSQL. The agent itself is brought to life by the runtime Supervisor in the engine process, which reads that configuration on every turn. An agent is the unit of multi-tenancy: one Polyant deployment can host hundreds of agents side-by-side.
The DB tables, the REST API, and the schema still use the technical name instance (e.g. /api/instances, instance_id, instance_prompts). The human-facing label everywhere else is agent.
Concretely, when an operator says “the support bot”, that is an agent. When a developer hits /v1/chat/completions with "model": "support-bot", the slug resolves to one agent.
See: Agents.
Conversation
A conversation is a persistent thread of messages between an end user and an agent. Conversations are scoped to an agent and include user messages, assistant messages, tool calls, and metadata. Every conversation has an auto-generated title and a rolling summary, and survives engine restarts.
Memory
Memory is the agent’s long-term knowledge about people, preferences, facts, events, relationships, and decisions. Memory is separate from conversations: a fact extracted in February can resurface in an unrelated conversation in May.
Memory rows are stored in PostgreSQL with pgvector embeddings and a full-text index. Retrieval combines both signals using Reciprocal Rank Fusion (RRF). Memory is opt-in per agent via the memoryEnabled flag.
Memory is also written automatically: after every response a fire-and-forget background job analyses the turn and persists any new facts, tagged in ai_logs with callType: "service" so its cost is accounted separately from the conversation.
See: Memory.
Knowledge Base
Beyond extracted facts, an agent can hold longer-form notes — meeting recaps, user preferences, completed-activity logs, reference snippets. The Knowledge Base lives alongside memory and is curated, not auto-extracted; the agent itself can append to it via the writeKnowledge tool.
See: Knowledge Base.
Skill
A skill is a reusable capability bundle: a focused prompt fragment, optional scripts, and an optional list of required environment variables. Skills live in a global catalog and are enabled per agent. Think plug-ins — instead of bloating every agent’s identity prompt with every possible behavior, keep the identity short and let skills attach situational expertise.
See: Skills.
Tool
A tool is an atomic action the agent can take during a turn: search memory, send a Slack message, create a HubSpot contact, schedule a future task.
Tool definitions live in code, not in the database. Each tool is a TypeScript file under packages/engine/src/agents/tools/*.tool.ts that calls registerTool({...}) at module load. At engine boot, loadAllTools() scans the directory, every tool registers itself, then syncToolsToDb() mirrors the registry into a tools catalogue table (and removes catalogue rows for tools deleted from code, cascading through instance_tools).
The only runtime-editable surface is per-agent enablement: the instance_tools table holds one row per (agent, tool) with an enabled flag, and the admin panel’s Tools tab toggles those rows. Creating a new tool or editing an existing tool’s behaviour is a pull-request, not an admin action.
updateSoul — agent self-customization
A handful of tools let the agent persist changes to its own configuration. The most notable is updateSoul (packages/engine/src/agents/tools/update-soul.tool.ts), which rewrites the agent’s 02-soul prompt section. When a user says “from now on always answer in Italian and keep replies short”, the agent calls updateSoul (after confirmation) and the new behaviour persists for every future conversation. A sibling tool, updateUserProfile, updates the 07-user-identity section with facts about the user.
See: Tools.
Channel
A channel is the surface where end users (or other systems) meet the agent. Polyant distinguishes two related concepts:
ChannelType— the narrow, admin-API-configurable set of transports with per-agent encrypted credentials:telegram,slack,whatsapp,agent.MessageChannelType— the wide set of every possible source of an inbound pipeline message. It includes the four above plusweb(OpenAI-compatible HTTP API and Playground),scheduled(cron-style tasks), androom(event-driven cycles) — seven message sources in total.
The three transport adapters (Telegram via grammY long polling, Slack via Bolt Socket Mode, WhatsApp via Twilio webhook) start, stop, and reconnect at runtime — no engine restart required.
See: Channels.
How agents run
An agent is not just a request/response loop. Polyant ships four execution mechanisms; an agent typically uses several at once.
1. Inbound message (synchronous)
A user sends a message on any channel → the inbound pipeline runs immediately → the supervisor calls tools and produces a reply on the same channel → the conversation history is persisted.
- Trigger: human-initiated message.
- State left behind: appended turns on an existing conversation; updated summary; fire-and-forget memory extraction.
- Pick when: the agent is reacting to a human in real time.
2. Webhook (event-driven, immediate)
An external system POSTs to /webhooks/:webhookToken. An LLM matcher checks the payload against the agent’s event_definitions; on first match, a brand-new conversation is opened with a contextPrompt rendered from the payload, and the supervisor runs once.
- Trigger: external HTTP event (HubSpot deal closed, Stripe invoice paid, GitHub push).
- State left behind: a fresh conversation; outbound message(s) on the configured channel; audit log entries.
- Pick when: an external event must cause the agent to act now.
See: Room (covers both webhooks and rooms).
3. Room (event-driven, batched)
Webhooks (and other event producers) deposit events into a per-agent backlog (capped at 100). Every 30 seconds the room scheduler ticks: if any agent has pending events, it fires a ReAct cycle that drains the backlog and lets the supervisor decide how to react — typically writing to the room’s outbound channel and marking events as handled via the mark_events_completed harness tool.
- Trigger: the 30s tick, when the backlog is non-empty.
- State left behind: a new conversation per cycle (
room:{agentId}:{timestamp}); outbound messages; updatedroom_activity_log; backlog rows flipped tocompleted. - Pick when: events can be debounced or batched (“every 30s, look at everything that happened and decide what to do”).
See: Room.
4. Scheduled Tasks
Cron-like, declaratively configured per agent in the scheduled_tasks table. Fires at a wall-clock time with a frozen taskPrompt and a per-task outbound channel.
- Trigger: the scheduler at the configured time (cron / interval / one-shot).
- State left behind: a new conversation tagged
channel = scheduled; outbound messages on the task’s channel. - Pick when: the action depends on time, not on an external event — daily reports, weekly digests, scheduled follow-ups.
Provider tiers
Polyant abstracts model selection through three tiers: fast, standard, and heavy. Each agent picks one provider (OpenAI, Anthropic, or AWS Bedrock) and, optionally, pins a specific model — the tier abstraction lets you swap providers per agent without touching pipeline code. See AI Gateway for the tier-to-model mapping and the per-instance override rules.
High-level architecture
+-------------------------------------------------+
| Admin Panel (Next.js) |
| agent + ops management |
+--------------------+----------------------------+
| REST API
+--------------------+----------------------------+
| Engine (NestJS) |
+-------------------------------------------------+
| HTTP Server - OpenAI-compatible API |
| Channel Layer - Telegram, Slack, WhatsApp, |
| Web, Scheduled, Room, Agent |
| Agent Layer - Supervisor + Tool Registry |
| Room - Event-driven proactive cycles|
| Webhooks - External event ingestion |
| Scheduled Tasks - Cron / interval / one-shot |
| STT Gateway - Voice-note transcription |
| Memory Layer - pgvector + PG FTS + RRF |
| AI Gateway - tier abstraction, cost log |
| Activity Stream - In-process pub/sub bus (SSE) |
| Audit Layer - Per-tool-call audit trail |
| Crypto Layer - AES-256-GCM secret encryption|
| Data Layer - PostgreSQL 16 (Drizzle ORM) |
+-------------------------------------------------+For a deeper architectural deep-dive (modules, message pipeline, schema), see Architecture.