π Website: polyant.ai Β Β·Β π Docs: docs.polyant.it Β Β·Β π¬ GitHub: polyant-ai/polyant
Polyant is an open-source platform for building and deploying AI assistants with long-term memory, multi-channel support, and full per-instance customization. It provides a complete runtime for multi-agent systems with an OpenAI-compatible API, a NestJS engine, and a Next.js admin panel β batteries included.
The name comes from Hofstadter's GΓΆdel, Escher, Bach β specifically the "Ant Fugue" dialogue and the character of Aunt Hillary, an ant colony understood as the archetype of emergent intelligence: individual agents, each one limited, that produce β by coordinating β a collective intelligent behaviour that exceeds the sum of its parts. It is, literally, the thesis we are pitching: fleets of specialised agents that, when orchestrated, generate performance impossible for any single agent. Poly- (classical Greek, "many") makes the key concept explicit: coordinated multiplicity.
Many agents. One mind.
Polyant was conceived in the wake of the OpenClaw release. OpenClaw was a watershed moment for the agent ecosystem: it showed, in working code, what a reactive personal AI assistant could feel like and β more importantly β how to build the harness around the model: the loop, the tool dispatch, the message lifecycle, the guard rails. For the first time, the engineering pattern behind a serious assistant was readable, hackable, and reproducible outside a vendor-controlled platform.
We took OpenClaw apart, studied its design, and used it as the starting point for an analysis of what a multi-tenant, enterprise-grade evolution of that idea would need. Several technological choices in Polyant echo OpenClaw directly β the tool registry pattern, the supervisor-as-loop architecture, the markdown-driven skill system, the tier abstraction over models β because that vocabulary turned out to be the right one for this class of system.
From that foundation we set out to answer a different question: what does it take to run this kind of assistant inside an organization? The answer drove most of the layers you see today and pushed Polyant toward a web-based product rather than a CLI:
- A multi-instance model, so a single deployment can serve different assistants β each with its own personality, tools, secrets, and channels β without code branching.
- An admin panel as the primary surface, because the people who configure assistants in a company are not always the people who can edit a config file.
- Per-instance encryption of every secret (AES-256-GCM), so credentials for one assistant cannot leak into another tenant's blast radius.
- A proactive Room engine alongside the reactive chat loop, because real assistants do not only answer β they observe events and act.
- An OpenAI-compatible API as the default integration surface, so any client (Open WebUI, custom apps, scripts) can talk to any instance with zero adaptation.
Polyant is, in short, what happens when you take the architectural lessons of OpenClaw, hold them up against the requirements of building assistants that real teams can deploy, govern, and trust β and then ship the result as open source.
- Supervisor Agent β Central orchestrator with tool use, up to 15 reasoning steps per request (Vercel AI SDK)
- Long-term Memory β Automatic fact extraction via LLM; hybrid search with pgvector cosine similarity + PostgreSQL FTS fused via Reciprocal Rank Fusion
- Multi-channel β Telegram, Slack, WhatsApp, and an OpenAI-compatible HTTP API (with file attachment support)
- Provider-agnostic β Switch between OpenAI and Anthropic per-instance via the admin panel; tier abstraction (
fast | standard | heavy) decouples code from model names - Self-registering Tools β Drop a
*.tool.tsfile in the tools directory; it auto-registers at boot with no wiring needed - Skill System β Markdown-based skill definitions stored in the database; per-instance encrypted env vars for skills that need API keys
- Multi-instance β Independent configuration of prompts, skills, tool availability, and identity per instance; instances exposed as selectable "models" via the OpenAI-compatible API
- Per-instance Secrets β API keys, channel config, and LangSmith settings stored AES-256-GCM encrypted per instance
- Admin Panel β Next.js 15 frontend for managing instances, conversations, memories, skills, tools, channels, and analytics
- Event-driven Room β Proactive agent workspace that processes webhook events on a 30-second tick and can push outbound messages
- Conversation Tracking β Full message history with summaries and full-text search in PostgreSQL
- Analytics β Token usage, cost tracking, and pipeline latency per instance
- Cost Monitoring β Every LLM call logged with token counts and estimated USD cost
- File Attachments β Photos and PDFs from WhatsApp/Telegram stored in S3, passed as multimodal content to the LLM
The full documentation lives at docs.polyant.it (source: polyant-ai/docs).
- Getting Started β build your first agent in 10 minutes
- Channels Setup β Telegram, Slack, WhatsApp recipes
- Examples β minimal instance, skill, and tool templates
- Deployment β Docker Compose, Render, Fly.io, Kubernetes
- Architecture β full technical deep dive
- Glossary β Instance, Tier, Room, Skill, Tool explained
git clone https://github.com/polyant-ai/polyant.git
cd polyant
npm installdocker compose up -dStarts PostgreSQL 16 with pgvector on port 5432.
cp .env.example .envSet the required variables (see .env.example for descriptions):
# Generate encryption key
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Generate auth secret
openssl rand -base64 32npm run db:migrate # create all tables
npm run dev # engine on :4000
npm run dev:web # admin panel on :3001 (separate terminal)Open http://localhost:3001, create an instance, and configure your AI provider keys in the Settings tab.
ββββββββββββββββββββββββββββββββββββββββββββββββ
β packages/web (Next.js 15) β
β Admin Panel β instance management β
βββββββββββββββββββ¬βββββββββββββββββββββββββββββ
β REST API + cookie auth
βββββββββββββββββββ΄βββββββββββββββββββββββββββββ
β packages/engine (NestJS 11) β
ββββββββββββββββββββββββββββββββββββββββββββββββ€
β HTTP Server OpenAI-compatible API β
β Channel Layer Telegram Β· Slack Β· WhatsApp β
β Agent Layer Supervisor + Tool Registry β
β Memory Layer pgvector + PG FTS + LLM β
β AI Gateway Tier abstraction + logging β
β Room Engine Event-driven proactive loop β
β Crypto Layer AES-256-GCM encryption β
β Data Layer PostgreSQL 16 (Drizzle ORM) β
ββββββββββββββββββββββββββββββββββββββββββββββββ
See Architecture for the full technical reference.
polyant/
βββ packages/
β βββ engine/ # @polyant/engine β NestJS AI runtime + API
β β βββ src/
β β βββ agents/ # Supervisor, tools registry, sub-agent types
β β βββ ai-gateway/ # Provider-agnostic LLM abstraction (tier-based)
β β βββ channels/ # Telegram, Slack, WhatsApp adapters
β β βββ memory/ # pgvector embeddings + hybrid search
β β βββ room/ # Event-driven proactive agent workspace
β β βββ instances/ # Instance CRUD, secrets, config resolver
β β βββ skills/ # Global skill library CRUD
β β βββ server/ # NestJS controllers (REST + OpenAI-compat)
β βββ web/ # @polyant/web β Next.js admin panel
β βββ src/app/
β βββ (auth)/ # Google OAuth login
β βββ (admin)/ # Protected admin routes
βββ examples/ # Minimal working examples (instances, skills)
βββ docker-compose.yml # PostgreSQL + pgvector
| Concept | Description |
|---|---|
| Instance | A named assistant configuration with independent prompts, skills, tools, and secrets |
| Tier abstraction | Code requests fast | standard | heavy; model mapping lives in ai-gateway/config.ts |
| Tool registry | Tools self-register at boot via registerTool() β no hardcoded imports |
| Skill system | Markdown skill definitions in DB; encrypted per-instance env vars for API keys |
| Room | Event-driven workspace that runs a ReAct cycle on webhook-triggered events |
| Fire-and-forget | Post-response tasks (memory extraction, summary) run async without blocking the user |
| Command | Description |
|---|---|
npm run dev |
Start engine with hot reload (tsx watch, port 4000) |
npm run dev:web |
Start Next.js admin panel (port 3001) |
npm run build |
Build all packages |
npm start |
Run engine from compiled output |
npm run db:generate |
Generate Drizzle migrations from schema |
npm run db:migrate |
Apply pending migrations |
npm run db:studio |
Open Drizzle Studio GUI |
npm test |
Run all tests |
npm run test:unit |
Unit tests only (no DB required) |
npm run test:integration |
Integration tests (requires PostgreSQL) |
npm run lint |
ESLint all packages |
npm run typecheck |
TypeScript check all packages |
| Channel | Protocol | Notes |
|---|---|---|
| HTTP API | OpenAI-compatible (/v1/chat/completions) |
Instances appear as selectable models |
| Telegram | Long polling (grammY) | Text, photos, document attachments |
| Slack | Socket Mode (@slack/bolt) | Per-instance configuration |
| Webhook via Twilio | Text and media attachments |
All channel configs are stored encrypted per-instance. Adapters start/stop dynamically without a restart.
See GitHub Issues and Discussions for the live list of planned features and open requests. The items below describe the major directions we want Polyant to grow in, grouped by intent.
- Multi-tenancy β formalize the Organization β Project β Instance hierarchy already sketched in the auth module (Phase 2). Adds invitation-based memberships, configurable RBAC, and tenant-scoped URLs (
/organizations/{org}/projects/{project}/instances/{slug}/...). Schema design (organizations,projects,organization_memberships,roles,invitations) is documented; not yet implemented. - Pluggable memory backend β today the memory layer is hard-wired to OpenAI for embeddings (the per-instance
openai_api_keysecret is required regardless of the assistant's chat provider, because Anthropic has no embedding API). The roadmap is to introduce aMemoryProviderabstraction so that embeddings can come from Voyage, Cohere, local models (e.g. via Ollama / a locally hosted bge / nomic), or a self-hosted gateway β just like the chat layer already is provider-agnostic via the AI Gateway tiers. - Sandboxed tool execution β high-impact tools (anything that runs git, executes shell, writes files, or talks to a customer's infrastructure) should not run inside the engine process. We want to push these into an external sandbox (firecracker / gVisor / a remote isolate-style runner) with a tight contract: tool input β sandbox β tool output. The current trade-offs (e.g. the
gitCloneRepotoken written under.git/polyant-tokenwhile the workspace exists) become non-issues once execution is moved off-host. - Evaluation suite β simulation-based regression testing for assistants: digital twins, scenario libraries, golden conversations, and a CI integration so that changing a prompt or skill produces a measurable delta.
- Voice channel β bidirectional voice as a first-class adapter alongside Telegram / Slack / WhatsApp.
- Web widget β embeddable chat surface that talks to an instance directly via the OpenAI-compatible API.
- Channel-level analytics β per-channel cost, latency, error rate (today analytics are aggregated per instance).
- Self-service skill editor in the admin panel β today skills are edited as markdown via API; an in-product editor with version diffing is on the list.
- Tool scaffolding CLI β
npm run create-tool <name>to drop a*.tool.tsskeleton wired to the registry. - Drizzle migration ergonomics β the current ESM workaround for
drizzle-kit generate(running it vianpx tsx ../../node_modules/drizzle-kit/bin.cjs generate) and the lack of snapshot files force migrations to be hand-edited. We want to either fix the toolchain interaction or migrate the schema-diff workflow to an alternative that plays nicely with ESM monorepos.
These are deliberate trade-offs, deferred decisions, or rough edges that ship with Polyant today. They are listed here so that contributors and adopters know what they are picking up β and so that we can collect help and PRs against a shared list rather than a private wiki.
- Memory is locked to OpenAI β
packages/engine/src/memory/embedder.tscalls the OpenAI embeddings endpoint directly. An instance configured to use Anthropic for the chat tier still needs anopenai_api_keysecret if memory is enabled. Replacing this with aMemoryProviderinterface is a high-priority item on the roadmap above. - Critical tools run in-process β
gitCloneRepo, file system access, and any future shell-style tools execute in the engine's own runtime. The current safeguards (per-conversation workspace, ephemeral credentials at.git/polyant-tokenmode 0600, automatic cleanup) keep the blast radius small but do not isolate CPU, network, or filesystem at OS level. Moving tool execution to an external sandbox is on the roadmap. - Drizzle version mismatch between packages β
packages/web/src/lib/auth.tscasts the Drizzle adapter throughas any(4 sites) becausepackages/engineandpackages/webpin differentdrizzle-ormversions. Works today, but it's brittle β a single version pin across the workspace is the proper fix. workspaces/directory is a leftover β the filesystemworkspaces/<instanceId>/tree is documented as legacy and only used for knowledge-file sync. The intent is to either fold knowledge into the database (consistent with the rest of the configuration model) or to formalizeworkspaces/as a sandbox root.
- Fire-and-forget post-processing swallows failures β message persistence, summary updates, and memory extraction run async after the user reply (
pipeline.ts). On error they currently log viaconsole.errorand move on. There is no retry, no dead-letter queue, and no surfacing in the admin panel β a failed memory write is invisible to operators. - Structured logging is incomplete β several boot/runtime paths still use
console.log/console.error(the project's own coding rules forbid this in production code). We want a single structured logger across engine and web with consistent fields (instanceId, conversationId, requestId). - Webhook backlog drops events silently β
POST /webhooks/:tokenalways returns200 OKand drops events when the per-instance backlog cap (100) is reached. There is no operator-facing signal. A bounded queue with overflow alerting is the planned fix. - Rate limiting is uneven β the OpenAI-compatible endpoint is throttled, but
/memoriesand several management endpoints have no per-tenant rate limits. Memory-write spam from a misbehaving client is not prevented today. - Activity-log compaction is described but not scheduled β Room activity is documented as auto-compacted (
7d daily β weekly β monthly) but no scheduled job actually runs the compaction step yet. Tables grow until manually pruned.
SubAgentDefinitionis unused β the type is defined inpackages/engine/src/agents/sub-agents/types.tsand a place-holder for specialized sub-agents (researcher, analyst, β¦). TodayspawnTaskcreates ad-hoc agents that don't reference it. Either wire it up or delete the type until it's needed.- WhatsApp template fallback is a stub in OSS β
channels/adapters/whatsapp/stub-templates.tsships with an emptySTUB_TEMPLATESmap. Operators using WhatsApp's strict 24-hour session window must populate it with their own approved templates; otherwise the adapter falls back to a compact summary string. - Files exceeding the 400-line house rule β a few files in
packages/web/src/still bundle multiple responsibilities and are due for a split.
- The "Phase 2 β Multi-Tenancy" section of
CLAUDE.mddescribes a hierarchy that does not exist in the schema yet; this is a roadmap document, not a description of current behavior. - Trade-offs around the
gitCloneRepocredential lifecycle (token at rest while the workspace exists) are documented inCLAUDE.mdbut should be surfaced on docs.polyant.it as well, since they affect deployment posture.
If you would like to take on any of the items above, please open an issue first so we can scope it together β most of these decisions involve trade-offs we are happy to discuss in the open.
Contributions are welcome! Please read CONTRIBUTING.md for setup instructions, coding conventions, and the PR process.
For vulnerability reports, see SECURITY.md β please do not file public issues for security bugs.
| Layer | Technology |
|---|---|
| Monorepo | npm workspaces |
| Language | TypeScript / Node.js (ESM) |
| Agent Framework | Vercel AI SDK v4 |
| Engine Server | NestJS 11 |
| Admin Panel | Next.js 15, React 19, Tailwind CSS 4, shadcn/ui |
| Database | PostgreSQL 16 + pgvector (Drizzle ORM) |
| Memory | pgvector cosine similarity + PostgreSQL FTS (RRF fusion) |
| Encryption | AES-256-GCM (Node.js crypto) |
| Auth | Auth.js v5 (Google OAuth, JWT/JWE) |
| Tracing | LangSmith |
| Infrastructure | Docker Compose |
Polyant is licensed under the GNU Affero General Public License v3.0.