Skip to content

polyant-ai/polyant

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

18 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Polyant

Polyant

License: AGPL v3 Node.js 22 TypeScript

🌐 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.

Background

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.

Features

  • 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.ts file 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

Documentation

The full documentation lives at docs.polyant.it (source: polyant-ai/docs).

Get started

Operate

  • Deployment β€” Docker Compose, Render, Fly.io, Kubernetes

Understand

  • Architecture β€” full technical deep dive
  • Glossary β€” Instance, Tier, Room, Skill, Tool explained

Quick Start

Prerequisites

1. Clone and install

git clone https://github.com/polyant-ai/polyant.git
cd polyant
npm install

2. Start infrastructure

docker compose up -d

Starts PostgreSQL 16 with pgvector on port 5432.

3. Configure environment

cp .env.example .env

Set 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 32

4. Run migrations and start

npm 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.

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         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.

Project Structure

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

Key Concepts

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

Commands

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

Channels

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
WhatsApp Webhook via Twilio Text and media attachments

All channel configs are stored encrypted per-instance. Adapters start/stop dynamically without a restart.

Roadmap

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.

Architectural directions

  • 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_key secret is required regardless of the assistant's chat provider, because Anthropic has no embedding API). The roadmap is to introduce a MemoryProvider abstraction 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 gitCloneRepo token written under .git/polyant-token while 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.

Channels & UX

  • 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).

Developer experience

  • 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.ts skeleton wired to the registry.
  • Drizzle migration ergonomics β€” the current ESM workaround for drizzle-kit generate (running it via npx 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.

Known Open Issues

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.

Architecture & coupling

  • Memory is locked to OpenAI β€” packages/engine/src/memory/embedder.ts calls the OpenAI embeddings endpoint directly. An instance configured to use Anthropic for the chat tier still needs an openai_api_key secret if memory is enabled. Replacing this with a MemoryProvider interface 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-token mode 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.ts casts the Drizzle adapter through as any (4 sites) because packages/engine and packages/web pin different drizzle-orm versions. Works today, but it's brittle β€” a single version pin across the workspace is the proper fix.
  • workspaces/ directory is a leftover β€” the filesystem workspaces/<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 formalize workspaces/ as a sandbox root.

Robustness

  • 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 via console.error and 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/:token always returns 200 OK and 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 /memories and 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.

Code quality & deferred design

  • SubAgentDefinition is unused β€” the type is defined in packages/engine/src/agents/sub-agents/types.ts and a place-holder for specialized sub-agents (researcher, analyst, …). Today spawnTask creates 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.ts ships with an empty STUB_TEMPLATES map. 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.

Documentation gaps

  • The "Phase 2 β€” Multi-Tenancy" section of CLAUDE.md describes 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 gitCloneRepo credential lifecycle (token at rest while the workspace exists) are documented in CLAUDE.md but 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.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for setup instructions, coding conventions, and the PR process.

Security

For vulnerability reports, see SECURITY.md β€” please do not file public issues for security bugs.

Tech Stack

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

License

Polyant is licensed under the GNU Affero General Public License v3.0.

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages