The open-source control plane and runtime for team AI agents
Project description
OpenLoop
Open-source control plane and runtime for team AI agents — persistent, asynchronous teammates that work across your channels (Slack, Discord, Zoom, GitHub, Linear), each with their own memory, tools, model policy, budget, approval rules, and audit trail.
Status: early / WIP. Not production-ready. APIs, config formats, and the commands below will change. Commands marked (preliminary) are placeholders.
Why
Most AI assistants are personal and single-player. Real work happens across shared channels, threads, calls, repos, and issues — and it spans more than one tool. The useful primitive isn't "a Slack bot" — it's a persistent team teammate that remembers your team's decisions, uses a scoped set of tools, routes tasks to the right model, stays in budget, asks before doing anything risky, and leaves an audit trail.
OpenLoop gives your team such an agent, reachable across the surfaces you already use, with an open-source runtime you can self-host and inspect. Slack/Discord/Zoom/GitHub/Linear are surfaces — the product is the agent runtime and control plane behind them. Memory, tools, and policy can be scoped per channel so context doesn't leak across teams.
For: engineering, data, and platform teams; AI-heavy startups; OSS maintainers; anyone who wants Claude Tag–style workflows without single-vendor lock-in.
How this differs from Claude Tag
Comparison based on Anthropic's Claude Tag announcement (June 2026). Claude Tag is evolving quickly — check the source for current details.
OpenLoop shares Claude Tag's core model — persistent, asynchronous, multiplayer team agents with tools and memory — and extends it in a model-agnostic, configurable, multi-surface, open-source direction. The first rows below are common ground; the rest are where OpenLoop goes further.
| Dimension | Claude Tag | OpenLoop |
|---|---|---|
| Persistent | Long-lived agent that stays active and retains team context | Long-lived agent that stays active and retains team context |
| Asynchronous | Event- and mention-driven; works in the background, replies when ready | Event- and mention-driven; works in the background, replies when ready |
| Multiplayer | Shared in team channels, not a personal assistant | Shared across team surfaces, not a personal assistant |
| Team context | Channel-level Claude identities with scoped memories and shared conversations | Configurable memory scope across channel, agent, or workspace |
| Tools | Admin-approved tool access inside Claude's managed product | Explicit MCP/native tool allowlists, approval gates, and auditable actions |
| Models | Claude-native / Anthropic-first | Model-agnostic routing across Anthropic, OpenAI, Gemini, Ollama, OpenRouter, or any LiteLLM-compatible provider |
| Configuration | Admin-managed product settings | Config-as-code agents for surfaces, memory, model policy, tools, approvals, and budgets |
| Surfaces | Slack first, with other workplace integrations planned | Designed as a surface-agnostic runtime for Slack, Discord, GitHub, Linear, Zoom, and more |
| Deployment | Managed Anthropic experience | Self-hostable, inspectable, open-source infrastructure |
| Best for | Teams that want a managed Claude-centered teammate | Teams that want multiplayer agents with provider choice, deeper policy control, and open infrastructure |
What it does (MVP)
- Summarize Slack/Discord threads and remember team decisions
- Create GitHub issues from discussions
- Investigate failing CI/builds
- Draft PRs via a coding worker, gated on human approval
- Track token/cost usage per channel, agent, task, and model
- Route tasks across providers (OpenAI, Anthropic, Gemini, Ollama, OpenRouter, any LiteLLM-compatible) — not only Claude
- Require human approval before risky write actions
Concepts
| Concept | Meaning |
|---|---|
| Workspace | Top-level tenant; owns agents, integrations, policy defaults. |
| Agent | A team agent reachable across surfaces — the unit of identity, memory, and policy. |
| Surface | Where you reach the agent: Slack, Discord, Zoom, GitHub, Linear. |
| Memory Scope | What an agent recalls; can be scoped per channel so context doesn't leak across teams. |
| Tool Policy | Explicit allowlist of tools (MCP / native) and their permissions. |
| Model Policy | Which model handles which kind of task. |
| Human Approval | Gates requiring a human before write/risky actions. |
| Budget | Per-agent (optionally per-channel) spend and token limits, tracked and enforced. |
How it works
Slack / Discord / Zoom / GitHub / Linear (surfaces)
│
▼
┌──────────────────┐ model policy ┌──────────────┐
│ Agent runtime │ ───────────────▶ │ Model gateway│ ─▶ OpenAI / Anthropic
│ │ │ (LiteLLM) │ Gemini / Ollama / ...
└───────┬──────────┘ └──────────────┘
│ tool policy memory · budget · audit
▼ ┌──────────────────────┐
┌──────────────┐ │ Postgres (pgvector) │
│ Tool gateway │ ──▶ GitHub └──────────────────────┘
│ (MCP) │ CI / coding worker / ...
└──────────────┘
write actions ─▶ human approval
A mention or event on any surface triggers the team's agent. The runtime loads its memory, tool policy, model policy, and budget; routes the task to a model; uses only allowed tools; pauses for approval on write actions; then records usage, cost, and outcome to the audit trail and memory.
Example: Slack
@dev-platform @agent summarize this thread and capture the decision
agent 📝 Summary (last 24 messages):
• Moving ingestion off the legacy queue.
• Redis Streams chosen over Kafka for v1 (lower ops overhead).
• Owner: @priya, target: end of next sprint.
🧠 Saved to channel memory: "Use Redis Streams for ingestion v1. Owner: @priya."
Open a GitHub issue to track it?
@dev-platform yes
agent ⏳ Write action (create issue in openloop/ingestion) — approval required.
@priya / @maintainers, approve? 💸 est. $0.004 · gpt-4o-mini
Example: agent config
Agents are config-as-code (apiVersion v1alpha1, preliminary). Full example:
agents/dev-platform.yaml.
apiVersion: openloop.ai/v1alpha1
kind: Agent
metadata: { name: dev-platform, workspace: acme }
spec:
surfaces:
- { type: slack, channel: "#dev-platform" }
- { type: discord, channel: "eng" }
memory: { scope: channel, backend: postgres, retention_days: 90 }
model_policy:
default: openai/gpt-4o-mini
routes:
- { match: { task: code }, model: anthropic/claude-sonnet-4-6 }
tools:
- { name: github, type: native, permissions: ["issues:write", "pulls:read"] }
approvals:
require_for: ["github.issues:write", "github.pulls:write"]
approvers: ["@priya", "@maintainers"]
budget: { monthly_usd: 50, per_task_usd: 0.50, on_exceeded: block }
Architecture
| Layer | Now | Later |
|---|---|---|
| API / backend | FastAPI | — |
| Agent runtime | async task pipeline | durable workflows (LangGraph-style) |
| Model gateway | LiteLLM | routing analytics |
| Tools | MCP gateway + native GitHub/Slack | more native connectors |
| Storage | Postgres + pgvector | — |
| Queue | Redis | — |
| Surfaces | Slack | Discord / Zoom / GitHub / Linear |
| Coding worker | — | OpenHands-style |
| Dashboard | — | Next.js |
| Observability | — | OpenTelemetry / Langfuse traces |
The open-source runtime covers: agent runtime, Slack integration, model adapters (LiteLLM), MCP tool gateway, local Postgres channel/thread memory, basic approval flow, basic token/cost tracking, Docker Compose deploy, and config-as-code agents.
Quickstart (preliminary — commands are placeholders)
Requires Docker + Compose and at least one model provider key.
git clone https://github.com/p1c2u/openloop.git
cd openloop
cp .env.example .env # set provider keys + Slack credentials
docker compose up -d # Postgres + Redis + runtime
openloop agents apply -f agents/dev-platform.yaml
# invite the bot to a channel, then: @agent summarize this thread
Nothing leaves your machine except calls to the providers/tools you configure.
Local development (preliminary)
The runtime is a Python/FastAPI app. Local dev uses mise to pin the toolchain and manage a project virtualenv — no global installs.
mise install # Python 3.12 + uv + an auto-created .venv
mise run install # install the runtime + dev deps (uv) into .venv
mise run test # run the test suite
mise run dev # FastAPI runtime with autoreload on :8000
mise run apply -- -f agents/dev-platform.yaml # validate an agent config
Try it against real Slack (Socket Mode)
Socket Mode opens an outbound WebSocket, so you can test a real mention →
reply → approval round-trip locally — no public URL or tunnel. In your .env
set a model key, SLACK_BOT_TOKEN (xoxb-…), and SLACK_APP_TOKEN (xapp-…,
created with the connections:write scope and Socket Mode enabled), then:
mise exec -- openloop slack socket # connects; mention the bot in a channel
Read-only observability while it runs: GET /usage (spend vs. budget) and
GET /audit (recent token/cost records).
End-to-end tests
The E2E suite is layered so each slower or less deterministic dependency is isolated.
A. Unit and integration tests: isolated logic tests plus in-process runtime, memory, usage, tool gateway, approval, Slack, MCP, and HTTP API tests. External providers, GitHub, and Postgres are faked, so this runs without credentials, Docker, or network:
mise run test
mise run test-unit # optional: only tests/unit
mise run test-integration # optional: only tests/integration
B. Postgres E2E: real Postgres/pgvector stores, fake model and fake GitHub. This validates SQL, asyncpg type handling, vector recall, approval persistence, and usage persistence:
mise run test-e2e
C. Runtime/GitHub live E2E: real model, approval gate, and real GitHub issue creation. It creates and then closes one issue, so it is explicitly opt-in:
export E2E_CONFIRM=1
export E2E_MODEL=groq/llama-3.3-70b-versatile
export GROQ_API_KEY=gsk_… # or set another LiteLLM provider key
export GITHUB_TOKEN=github_pat_… # issues:write on the repo
export E2E_GITHUB_REPO=you/sandbox
export DATABASE_URL=postgresql://openloop:change-me@localhost:5432/openloop # optional
mise run test-e2e-runtime-github-live
You can also invoke the live pytest target directly:
E2E_LIVE=1 GITHUB_TOKEN=… E2E_GITHUB_REPO=you/sandbox \
E2E_MODEL=groq/llama-3.3-70b-versatile GROQ_API_KEY=gsk_… \
mise exec -- python -m pytest tests/e2e/test_runtime_github_live.py -v
GitHub Actions runs unit and integration tests on pull requests and pushes to main.
The runtime/GitHub live E2E workflow is separate, runs nightly or manually, and
uses a protected live-e2e environment. Configure repository secrets
GROQ_API_KEY and LIVE_E2E_GITHUB_TOKEN; the latter should be a fine-grained
token with issue write access to openloop/openloop-e2e-sandbox.
D. Interactive Slack smoke (a human in the loop).
With SLACK_BOT_TOKEN + SLACK_APP_TOKEN set, run openloop slack socket,
mention the bot in a channel, and click Approve on a held write action.
E. Automated Slack live E2E: real Socket Mode round-trip with a stubbed
model, so it proves the Slack wire (auth, event delivery, in-thread reply)
without LLM nondeterminism. The triggering mention is posted with a user
token, not the bot token — Slack suppresses app_mention for messages an app
posts as itself, so a bot mentioning itself never fires the event. Add the
user-token scope chat:write (OAuth & Permissions → User Token Scopes) and
reinstall to get an xoxp-… token:
export E2E_LIVE=1
export SLACK_BOT_TOKEN=xoxb-… # chat:write, app_mentions:read, channels:history
export SLACK_APP_TOKEN=xapp-… # connections:write, Socket Mode enabled
export E2E_SLACK_USER_TOKEN=xoxp-… # user-token chat:write — posts the mention
export E2E_SLACK_CHANNEL=C0… # a channel the bot and that user are both in
export E2E_CONFIRM=1
mise run test-e2e-slack-live
The Slack live E2E GitHub Actions workflow is manual-only and uses a protected
slack-live-e2e environment. Configure environment secrets SLACK_BOT_TOKEN,
SLACK_APP_TOKEN, and E2E_SLACK_USER_TOKEN; set E2E_SLACK_CHANNEL as an
environment/repository variable, or pass a channel ID when manually dispatching
the workflow.
Roadmap
- Core async runtime + task pipeline
- Slack surface (mentions, threads, approvals)
- LiteLLM gateway + model-policy routing
- MCP tool gateway + native GitHub connector
- Channel/thread memory (Postgres + pgvector)
- Human approval flow + token/cost tracking
- Docker Compose + config-as-code
- Discord / Zoom / GitHub / Linear surfaces
- Coding worker (draft PRs)
- Durable workflows, Next.js dashboard, OTel/Langfuse tracing
Scope
This repository is the open-source runtime and control plane — self-hosted, inspectable, and the whole product for now.
It covers the agent runtime, model gateway (LiteLLM), MCP tool gateway + native connectors, channel/thread memory, approval flow, token/cost tracking, chat surfaces, config-as-code, and Docker Compose deployment. The roadmap above tracks what's planned.
Security
Agents act on your behalf — treat their credentials like a production service account.
- Least privilege: give each agent the narrowest tool scope it needs; never broad org-wide credentials.
- Approve writes: require human approval for creating issues/PRs, posting externally, or deleting anything.
- Scoped tokens: use fine-grained, per-integration tokens.
- Memory isolation: scope memory per channel so context doesn't leak.
- Secrets: keep them in
.envor a secrets manager — never commit them. - Inspect: self-host the runtime to see exactly what the agent does.
Early-stage software, no warranty. Don't connect sensitive production systems until you've reviewed the threat model for your environment.
Contributing
Early project — shaping the foundations is the most valuable work. Open an issue before anything non-trivial. Help wanted on the runtime, model adapters, MCP connectors, Slack surface, memory layer, and docs. See CONTRIBUTING.md.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyopenloop-0.0.1.tar.gz.
File metadata
- Download URL: pyopenloop-0.0.1.tar.gz
- Upload date:
- Size: 58.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eaf78ce5a33e1809870bea05471ec8da038dc190ddbfbff29bb58d69c6ff43a0
|
|
| MD5 |
4d23bb1947ca2758aac3924be68ceb61
|
|
| BLAKE2b-256 |
f202bac18e6ed37900f286500abcc4402ebb7318aebdada5ba660486fe4bb3f7
|
Provenance
The following attestation bundles were made for pyopenloop-0.0.1.tar.gz:
Publisher:
publish-pypi.yml on p1c2u/openloop
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyopenloop-0.0.1.tar.gz -
Subject digest:
eaf78ce5a33e1809870bea05471ec8da038dc190ddbfbff29bb58d69c6ff43a0 - Sigstore transparency entry: 1977939564
- Sigstore integration time:
-
Permalink:
p1c2u/openloop@7b8e84cc6c4d5aeb0da0501905c920153a8ab8c0 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/p1c2u
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@7b8e84cc6c4d5aeb0da0501905c920153a8ab8c0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyopenloop-0.0.1-py3-none-any.whl.
File metadata
- Download URL: pyopenloop-0.0.1-py3-none-any.whl
- Upload date:
- Size: 49.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d1072acacef7d85fefcc107c2c32ca0762d809c2888d11ccc95b3675e5a99cea
|
|
| MD5 |
707321bedfeb2361a5f2cdb8c093e577
|
|
| BLAKE2b-256 |
5f40727f78bbb3e5bd7192422f1f8bf57d5e9f429adb38934c1a11a837df4993
|
Provenance
The following attestation bundles were made for pyopenloop-0.0.1-py3-none-any.whl:
Publisher:
publish-pypi.yml on p1c2u/openloop
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyopenloop-0.0.1-py3-none-any.whl -
Subject digest:
d1072acacef7d85fefcc107c2c32ca0762d809c2888d11ccc95b3675e5a99cea - Sigstore transparency entry: 1977939660
- Sigstore integration time:
-
Permalink:
p1c2u/openloop@7b8e84cc6c4d5aeb0da0501905c920153a8ab8c0 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/p1c2u
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@7b8e84cc6c4d5aeb0da0501905c920153a8ab8c0 -
Trigger Event:
push
-
Statement type: