
Research
/Security News
GlassWASM: WebAssembly Malware Found in Trojanized Open VSX Extensions
The trojanized extensions use TinyGo-compiled WebAssembly and Solana transaction memos to resolve command-and-control infrastructure.
The open backend for AI agents.
Define your agent, deploy it, and get a fully working API with memory, tools, sandboxing, completions — out of the box.
Docs · Website · Discord · Issues
Polpo is an open-source runtime for building, running, and managing AI agents. It provides the infrastructure layer so you can focus on what your agents do, not how they run.
/v1/chat/completions endpointpolpo create, polpo dev, polpo deploynpx polpo create
Scaffolds a new Polpo project (cloud + local) with an interactive wizard: pick an org, a project name, and a template. Link an existing project instead:
npx polpo link --project-id <id>
Install globally so polpo is on your PATH:
npm i -g @polpo-ai/cli
The local server starts on http://localhost:3890. Open the API at /api/v1/health.
import { Orchestrator } from "polpo-ai";
const orchestrator = new Orchestrator("./my-project");
await orchestrator.init();
await orchestrator.run();
| Package | Description | npm |
|---|---|---|
polpo-ai | Main package -- CLI, server, orchestrator | |
@polpo-ai/core | Pure business logic, zero Node.js deps | |
@polpo-ai/drizzle | Drizzle ORM stores (SQLite + PostgreSQL) | |
@polpo-ai/server | Hono route factories (shared between OSS and cloud) | |
@polpo-ai/sdk | TypeScript client SDK | |
@polpo-ai/react | React hooks (TanStack Query + SSE) | |
@polpo-ai/tools | Extended tool definitions | |
@polpo-ai/vault-crypto | Encryption for vault secrets |
@polpo-ai/core Pure logic, types, state machine, store interfaces
|
@polpo-ai/drizzle SQLite + PostgreSQL store implementations
|
polpo-ai Node.js shell: orchestrator, CLI, Hono server, tools
|
@polpo-ai/server Shared Hono route factories
@polpo-ai/sdk Client SDK (fetch + SSE)
@polpo-ai/react React hooks wrapping the SDK
Core contains zero Node.js dependencies. The shell (polpo-ai) wires concrete adapters: file stores, Drizzle stores, the LLM engine, and the HTTP server.
Polpo supports three storage backends:
// .polpo/polpo.json
{
"settings": {
"storage": "file" // default -- JSON/MD files in .polpo/
// "storage": "sqlite" // better-sqlite3 via Drizzle
// "storage": "postgres" // PostgreSQL via Drizzle
}
}
Agents get access to tools based on their configuration. Built-in tool groups:
Loops are project-level deterministic graphs stored in .polpo/loops/*.json and assigned to agents from .polpo/agents.json. This avoids duplicating loop definitions across agents: a loop has name, context, start, and steps; an agent has assignedLoops and defaultLoop.
Use type: "tool" for deterministic sandbox/tool actions without an LLM turn, and toolChoice on type: "agent" when the model should still reason but must use a tool. Secrets stay in Vault; loop JSON should only contain non-secret input, while custom tools resolve credentials with ctx.vault.
.polpo/loops/router-flow.json:
{
"name": "router-flow",
"context": "shared",
"start": "clone_repo",
"steps": {
"clone_repo": {
"type": "tool",
"tool": "clone_repository",
"input": {
"repoUrl": "https://github.com/acme/app.git",
"targetDir": "workspace/app"
},
"saveAs": "repo.clone",
"next": "classify"
},
"classify": {
"type": "agent",
"systemPrompt": "Classify the incoming request.",
"tools": ["read"],
"skills": ["classification"],
"output": {
"schema": {
"type": "object",
"properties": {
"route": { "type": "string" }
}
}
},
"stopWhen": { "expression": "classify.route != null" },
"next": [
{ "when": "classify.route == 'answer'", "to": "answer" },
{ "to": "human_review" }
]
},
"answer": {
"type": "agent",
"systemPrompt": "Answer using the selected route.",
"tools": ["write"],
"toolChoice": { "mode": "required", "tool": "write" },
"next": "end"
},
"human_review": {
"type": "human",
"output": {
"schema": {
"type": "object",
"properties": {
"decision": { "type": "string" }
}
}
},
"next": "end"
}
}
}
.polpo/agents.json:
[
{
"agent": {
"name": "router",
"role": "Deterministic request router",
"runtime": "polpo-runner",
"assignedLoops": ["router-flow"],
"defaultLoop": "router-flow"
},
"teamName": "default"
}
]
Loop guards use Polpo's safe expression evaluator instead of JavaScript eval or new Function. Step outputs are available in the shared context bag by step id or saveAs path, e.g. classify.route, review.approved, or timing.start. saveAs writes context data; it does not create shell variables inside later bash commands. The OSS surface validates and round-trips the contract through core types, API schemas, SDK types, polpo deploy, and polpo pull.
Loops also have first-class governance fields:
permissions: readable allow/deny/approval rules for resources such as tool, step, model, human, and loop. Use this for least-privilege runtime constraints beyond an agent's broad tool assignment.policies: expression-based gates for advanced compliance rules.hooks: deterministic tool actions at lifecycle points such as loop:start, tool:before, tool:after, and loop:end.loop_trace: durable runtime events including permission.result, policy.result, approval.required, tool calls, transitions, and step outcomes.When a permission or policy requires approval, the runtime stores a checkpoint on the loop run. Approving the gate moves the run to approval_approved; POST /loop-runs/:id/resume continues from the saved context and remaining steps without replaying completed steps.
You can also keep loops as code and compile them to the same canonical contract:
// .polpo/loops/router-flow.ts
import { defineProjectLoop } from "@polpo-ai/core/loop-code";
export default defineProjectLoop({
version: "1",
kind: "graph",
name: "router-flow",
context: "shared",
permissions: [
{
id: "router-tool-allowlist",
resource: "tool",
action: "call",
effect: "allow",
match: { tool: ["read", "write"] }
}
],
start: "classify",
steps: {
classify: {
type: "agent",
systemPrompt: "Classify the incoming request.",
tools: ["read"],
next: "answer",
},
answer: {
type: "agent",
systemPrompt: "Answer using the selected route.",
tools: ["write"],
next: "end",
},
},
});
CLI support:
polpo loops validate
polpo loops compile .polpo/loops/router-flow.ts --out .polpo/loops/router-flow.json
polpo deploy
Agent-direct chat can target a loop explicitly:
{
"agent": "router",
"loop": "router-flow",
"messages": [{ "role": "user", "content": "Route this request" }]
}
At runtime, the selected project loop can narrow the effective prompt, tools, skills, model, reasoning, tool choice, and max turns per agent step. If a step omits skills, it inherits the agent-level skills. Project loop execution in chat completions uses the shared context graph: deterministic tool steps run first, store outputs in the context bag, and later agent steps receive that context as runtime data in their system prompt. Core keeps a compatibility normalizer for legacy inline loops + pipeline configs and ships a pure PipelineExecutor for sequential, tool, switch, parallel, and human nodes; hosts wire runLoop, runTool, and handleHuman callbacks to their concrete runtime.
Project loops also support governance fields:
{
"version": "1",
"kind": "graph",
"name": "governed-build",
"context": "shared",
"hooks": {
"loop:start": [
{ "tool": "unix_time", "saveAs": "timing.start" }
],
"tool:after": [
{ "tool": "audit_step", "input": { "level": "info" }, "saveAs": "audit.last", "onError": "continue" }
],
"loop:end": [
{ "tool": "unix_time", "saveAs": "timing.end" }
]
},
"policies": [
{
"id": "only-safe-tools",
"hook": "tool:before",
"effect": "allow",
"when": "tool.name == 'read' || tool.name == 'grep' || tool.name == 'unix_time'"
},
{
"id": "deny-shell",
"hook": "tool:before",
"effect": "deny",
"when": "tool.name == 'bash'",
"message": "bash requires an explicit build loop"
}
],
"start": "capture_start",
"steps": {
"capture_start": {
"type": "tool",
"tool": "unix_time",
"saveAs": "timing.start",
"next": "plan"
},
"plan": {
"type": "agent",
"systemPrompt": "Plan the work. Do not edit files.",
"tools": ["read", "grep"],
"next": "end"
}
}
}
Lifecycle hooks are deterministic tool actions run by the host runtime at loop:start, step:before, model:before, tool:before, tool:after, step:after, loop:transition, and loop:end. Hook when guards are evaluated against the shared context plus lifecycle payload such as step.name, step.type, tool.name, tool.input, and transition.from/to. Hook outputs are saved into the context bag with saveAs; onError: "continue" turns a failed hook into trace-only telemetry, while the default is fail-closed.
Policies are evaluated before hook actions at the same lifecycle point. deny fails the loop with LoopPolicyDeniedError, approval raises LoopApprovalRequiredError, and allow policies form an allow-list for that lifecycle point when at least one exists. If an allow-list is present and no allow rule matches, the loop is blocked.
When the host wires LoopRunStore, chat completions create durable loop runs, append every loop_trace event, and return loop_run_id. When the host also wires ApprovalStore, approval policies create a pending approval request and mark the loop run as awaiting_approval with approvalRequestId. The SDK exposes getLoopRuns() and getLoopRun(id) for audit/history surfaces. Streaming completions still emit each trace incrementally.
import { PolpoClient } from "@polpo-ai/sdk";
const client = new PolpoClient({
baseUrl: "http://localhost:3890",
});
const tasks = await client.getTasks();
const agents = await client.getAgents();
import { PolpoProvider, useTasks, useAgents } from "@polpo-ai/react";
function App() {
return (
<PolpoProvider baseUrl="http://localhost:3890">
<TaskList />
</PolpoProvider>
);
}
function TaskList() {
const { tasks, createTask } = useTasks();
// Real-time updates via SSE
return <ul>{tasks.map(t => <li key={t.id}>{t.title}</li>)}</ul>;
}
git clone https://github.com/lumea-labs/polpo.git
cd polpo
pnpm install
pnpm build
pnpm test
src/ Main package source
adapters/ Node.js runtime adapters (engine, filesystem, shell)
assessment/ Quality scoring and LLM review
cli/ Commander CLI commands
core/ Orchestrator wiring + re-exports from @polpo-ai/core
server/ Hono HTTP server + routes
stores/ File-based store implementations
tools/ Tool implementations (browser, email, PDF, etc.)
packages/
core/ @polpo-ai/core -- pure business logic
drizzle/ @polpo-ai/drizzle -- SQL store implementations
server/ @polpo-ai/server -- shared Hono route factories
client-sdk/ @polpo-ai/sdk -- TypeScript client
react-sdk/ @polpo-ai/react -- React hooks
tools/ @polpo-ai/tools -- tool definitions
vault-crypto/ @polpo-ai/vault-crypto -- encryption
examples/
chat-app/ React chat app example
Polpo Cloud is the managed version at polpo.sh. It uses the same open-source core with managed infrastructure: Neon PostgreSQL, sandboxed execution, and a dashboard.
Apache 2.0 -- Lumea Labs
FAQs
The open backend for AI agents
We found that polpo-ai demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
The trojanized extensions use TinyGo-compiled WebAssembly and Solana transaction memos to resolve command-and-control infrastructure.

Security News
Anthropic says the directive cited national security concerns over a narrow jailbreak, but offered no specific technical details.

Security News
A network of 152 Chrome live wallpaper extensions hid ad tracking and made extension-driven traffic look like Google search clicks.