惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 聂微东
Forbes - Security
Forbes - Security
IT之家
IT之家
P
Privacy International News Feed
宝玉的分享
宝玉的分享
小众软件
小众软件
Google DeepMind News
Google DeepMind News
美团技术团队
G
GRAHAM CLULEY
T
Tor Project blog
Recorded Future
Recorded Future
I
Intezer
C
Cyber Attacks, Cyber Crime and Cyber Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The Hacker News
The Hacker News
Hugging Face - Blog
Hugging Face - Blog
A
About on SuperTechFans
Scott Helme
Scott Helme
WordPress大学
WordPress大学
F
Full Disclosure
D
Docker
G
Google Developers Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Cyberwarzone
Cyberwarzone
The Last Watchdog
The Last Watchdog
V
V2EX
www.infosecurity-magazine.com
www.infosecurity-magazine.com
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Security Latest
Security Latest
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Recent Announcements
Recent Announcements
P
Palo Alto Networks Blog
L
LINUX DO - 热门话题
V
Visual Studio Blog
B
Blog RSS Feed
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
N
Netflix TechBlog - Medium
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
量子位
腾讯CDC
H
Heimdal Security Blog
博客园 - 【当耐特】
Simon Willison's Weblog
Simon Willison's Weblog
P
Privacy & Cybersecurity Law Blog
S
Securelist
Vercel News
Vercel News
J
Java Code Geeks

Hacker News: Show HN

PurrrrrFocus: Pomodoro Timer App - App Store Workflow Engine — Multi-Step Orchestration for Bun RapidPhoto: Pro Photo Editor App - App Store GitHub - think41/extrasuite: Token-efficient pull/edit/push workflow for AI agents editing Google Workspace files (Sheets, Docs, Slides, Forms) GitHub - DheerG/swarms: Achieve extraordinary results with claude code across a variety of tasks SPICE simulation → oscilloscope → verification with Claude Code — Lucas Gerads Show HN: VCoding – A 5 MB native Windows IDE with no dynamic dependencies Show HN: LLMs don't hallucinate because they're bad at math, it's the format GitHub - Agent-FM/agentfm-core: AgentFM is a peer-to-peer network that turns everyday computers into a decentralized AI supercomputer. AgentFM lets you run massive AI workloads directly across a global mesh of idle CPUs and GPUs. Show HN: Tracking Top US Science Olympiad Alumni over Last 25 Years GitHub - Potarix/agent-hub: One place to talk to all your agents Show HN: Runtime security for AI agents(injection,tool abuse, data exfiltration) GitHub - dubeyKartikay/lazyspotify: Terminal Spotify client for macOS and Linux GitHub - the-banana-tool/king-louie: Easy to use GUI Personal AI Assistant. Win/Linux/Mac. Show HN I made my vacation rental bookable by AI agents–no Airbnb, 0% commission GitHub - basteez/jsf-autoreload: maven plugin to enable hot reload on jsf projects uvm32/hosts/host-gdbstub at main · ringtailsoftware/uvm32 GitHub - labsai/EDDI: Config-driven engine that turns JSON into production-grade AI agents. Multi-agent orchestration, 12+ LLM providers, MCP/A2A protocols, RAG, persistent memory, and enterprise compliance (EU AI Act, GDPR, HIPAA). Built on Quarkus. GitHub - glitchnsec/fortyone-oss: AI Executive Assistant Platform Quickstart | Alien GitHub - muxshed/shed: One stream in, or many. Every destination, simultaneously. No cloud middleman, no per-channel fees, no limits. GitHub - ocrbase-hq/ocrbase: 📄 PDF/IMG ->.MD/JSON Document OCR API for PaddleOCR and GLMOCR. Self-hostable. GitHub - impactjo/home-memory: MCP server that lets your AI assistant remember everything about your home. GitHub - Sets88/dbcls: DbCls is a powerful terminal database client that supports various databases GitHub - neptun2000/heor-agent-mcp GitHub - SeanFDZ/macmind: Single-layer transformer in HyperTalk for the classic Macintosh RollQuation: Math Puzzles - Apps on Google Play GitHub - dropbox/witchcraft Show HN: Agent-cache – Multi-tier LLM/tool/session caching for Valkey and Redis LinkedIn™ 职位抓取工具 - Chrome 应用商店 GitHub - EdoardoBambini/Agent-Armor-Iaga: AI agents are getting tool access — shell, file system, databases, APIs, secrets. But **nobody is governing what they actually do with it**. Frameworks like LangChain, CrewAI, AutoGen, and Claude Code give agents the power to execute. Agent Armor gives you the power to control, audit, and approve every single action before it happens. HN Vibes — Week 15, Apr 7–13 2026 GitHub - chojs23/ec: Easy terminal-native 3-way git mergetool vim-like workflow GitHub - SethPyle376/hiraeth: Local AWS emulator focused on fast integration testing, with SQS support, SQLite-backed state, and a debug-friendly web UI. GitHub - JakOb-dotcom/cloud-sandbox-security-analysis: Technical analysis and Proof of Concept (PoC) regarding environment variable exfiltration in containerized cloud sandboxes via side-channel data leaks. Springboards - Flint Alpha Show HN: A simpler coding agent harness GitHub - audiodude/sudomake-friends GitHub - 256thFission/mini-mythos: OSS clone of Anthropic’s Mythos harness to locate C/C++ memory vulnerabilities Show HN: OpenParallax: OS-level privilege separation for AI agent execution Hacker News Sorted - Chrome 应用商店 Show HN: How to Install Docker on Ubuntu 24.04 LTS: Complete 2026 Guide GitHub - himanshudongre/smriti GitHub - sverrirsig/claude-control: macOS desktop dashboard for monitoring and managing multiple Claude Code sessions GitHub - ory/dockertest: Write better integration tests! Dockertest helps you boot up ephermal docker images for your Go tests with minimal work. Chiral - Chrome 应用商店 Show HN: Two Claudes collaborating through shared memory on a $100 mini-PC GitHub - pmichaillat/latex-cv: Minimalist LaTeX template for academic CVs GitHub - oguzbilgic/posse: A web UI for Anthropic Managed Agents. GitHub - sshiraz/depsly: Dependency risk analysis tool for npm packages ABI Add safari/agent-harness — Safari browser automation via safari-mcp by achiya-automation · Pull Request #212 · HKUDS/CLI-Anything GitHub - Halfblood-Prince/trustcheck: Verify PyPI package attestations and improve Python supply-chain security GitHub - oguzbilgic/kern-ai: Agents that do the work and show it. GitHub - bruits/satteri: High-performance Markdown and MDX processing for the JavaScript ecosystem GitHub - tylergibbs1/feedstock: High-performance web crawler and scraper for TypeScript, powered by Bun and Playwright GitHub - Grimm67123/grimmbot: The self-improving sandboxed and open-source AI agent. With persistent memory and scheduling. GitHub - whitevanillaskies/whitebloom: Local whiteboard that blooms. GitHub - hwdsl2/docker-whisper: Docker image for a self-hosted Whisper speech-to-text server with speaker diarization and OpenAI-compatible transcription and translation APIs. Powered by faster-whisper. Supports all Whisper models, NVIDIA GPU (CUDA) acceleration, JSON/SRT/VTT output, SSE streaming, offline mode, and multi-arch (amd64, arm64). GitHub - yisding/reviewwiggum GitHub - MarwanAlsoltany/serrors: Structured errors for Go: sentinel hierarchies, typed data, custom formatting, and slog integration. GitHub - soatok/age-php GitHub - Luthiraa/markitme GitHub - stagas/rtdiff: realtime git diff gui and AI-assisted commits GitHub - tombedor/excalicharts GitHub - wh1le/excalidraw-edit: Open and edit .excalidraw files from the terminal. Offline, auto-saves to disk. MalExt Sentry - Malicious Extension Scanner - Chrome 应用商店 GitHub - syi0808/asciianimesvg: Generate animated ASCII art SVGs from text. CLI, Rust library, WASM, and web editor. GitHub - zaina-ml/ml_forge: A visual-based graph node editor for training computer vision models. GitHub - anakin87/llm-rl-environments-lil-course: 🌱 A little course on Reinforcement Learning Environments for evaluating and training Language Models GitHub - takaakit/superpowers-uml: Superpowers-UML modifies Superpowers to ensure a software development workflow in which AI agents design through UML modeling. AdriByte Studio - Sviluppo Web e Soluzioni Digitali GitHub - chouligi/angel-copilot: Your personalized Angel Investment Advisor Show HN: MoodSense AI (ML and FastAPI and Gradio, Deployed on Hugging Face) Moodsense Ai - a Hugging Face Space by aman179102 GitHub - agenteractai/lodmem: Level Of Detail Context Management for Agents GitHub - ostefani/subnetlens: A fast, concurrent network scanner with a TUI and plain-text CLI, built in Go. It discovers live hosts on your network, scans their open ports, resolves hostnames, and fingerprints operating systems—delivered. Cyber Pulse: Agentic Intel - Apps on Google Play Whisper API: Self-Hostable Speech to Text Transcription The Agent-Web Protocol Stack: A Research Thesis GitHub - msmarkgu/RelayFreeLLM: A restful API designed to route user prompts to various AI model providers. Show HN: Provepy – A Python decorator that proves your code using Lean and LLMs Show HN: Pardonned.com – A searchable database of US Pardons GitHub - patrickdappollonio/dux: Dux is a terminal UI that lets you run multiple AI coding agents side by side, each in its own git worktree, with full companion terminals, macros, commit generation, and a command palette that knows more tricks than you do. kMC Crystal Simulator Show HN: HyperFlow – A self-improving agent framework built on LangGraph GitHub - stef41/vibescore: 🎵 Grade your vibe-coded project. One command, instant letter grade across security, quality, dependencies, and testing. GitHub - stef41/lmscan: 🔍 Detect AI-generated text and fingerprint which LLM wrote it. Open-source GPTZero alternative. Zero dependencies, works offline. imgur.com GitHub - visionscaper/collabmem: Enabling long-term collaboration with Agentic AI - building up episodic and world model memory over time with in-context awareness 在 Steam 上购买 FriedrichAI: Offline AI 立省 10% GitHub - atripati/ark: AI Runtime Kernel — a context operating system for AI agents. Eliminates tool bloat, loads only what’s needed, and gives LLMs their reasoning space back. GitHub - nowork-studio/toprank: Open-source Claude Code skills for SEO, SEM, Google Ads GitHub - tacomanator/sash: Lightweight macOS menu bar app for reliably cycling through windows of the current application. Appents | Social Media Management for Product-First Teams GitHub - pnhoang/youtube-spam-blocker: Automatically detects and hides spam messages in YouTube Live chat. Set rate limits, keyword filters, and block repeat offenders. GitHub - decisionnode/DecisionNode: CLI + Local MCP - A shared structured memory store across Claude Code, Cursor, Windsurf, Antigravity, and every MCP client. Semantically queryable. GitHub - AvaCodeSolutions/django-email-learning: An open source Django app for creating email-based learning platforms with IMAP integration and React frontend components. The $100K Gap in Kubernetes Security Tooling Function Calling Harness: From 6.75% to 100%
GitHub - opentalon/opentalon: OpenTalon is an open-source platform built from the ground up in Go as a robust alternative to OpenClaw
2026-04-16 · via Hacker News: Show HN

An open-source alternative to OpenClaw, built from scratch in Go.

CI License Go


What is OpenTalon?

OpenTalon is an open-source platform built from the ground up in Go as a robust alternative to OpenClaw. It is designed for individuals, teams, and large organizations that need a reliable, secure, and extensible solution — without the compromises that come with legacy codebases.

Why OpenTalon?

Existing solutions often suffer from:

  • Poor maintainability — tangled codebases that become harder to change over time
  • Low code quality — inconsistent patterns, lack of tests, and technical debt that compounds
  • Repeatable bugs — the same classes of issues resurfacing release after release
  • Hard to extend — adding features means forking or fighting the architecture
  • No smart model routing — you either pick one model and overpay, or manually juggle providers yourself
  • Every rule burns LLM tokens — business vocabulary, compliance checks, and formatting rules all get stuffed into the prompt, inflating cost and latency on every single request
  • No separation of business logic from AI — company-specific transformations (terminology, routing, validation) are tangled into prompts instead of handled by deterministic, testable code

OpenTalon is engineered for long-term quality from day one. Every architectural decision is made with maintainability, security, and stability in mind — so the project stays healthy as it grows.

First working example: console + hello-world plugin

Run OpenTalon in the terminal with the console channel and the hello-world plugin. When you type a message containing "hello", the plugin runs first (concatenates " world" and adds a random prompt fragment), then the LLM replies.

git clone https://github.com/opentalon/opentalon.git && cd opentalon
cp config.example.yaml config.yaml
export DEEPSEEK_API_KEY="your-key"   # or any OpenAI-compatible API key
make build setup                     # build core + clone & build plugin and channel
./opentalon -config config.yaml

Type a message and press Enter. Try hello — you get "hello world" plus a random question sent to the LLM; try something else — you get a guard message and no LLM call. Ctrl+C or Ctrl+D to exit. See hello-world plugin and docs/configuration.md.

Slash commands

With the opentalon-commands plugin (included in config.example.yaml), you can run built-in commands by typing a message that starts with /:

Command Description
/install skill <url> [ref] Install a skill from a GitHub URL; available immediately, no restart
/show config Show current config (secrets redacted)
/commands or /help List available slash commands
/set prompt <text> Set the editable runtime prompt (applies to the next message)
/clear or /new Clear the current conversation session

The plugin runs as the first content preparer: when your message starts with /, it parses the command and the core runs the built-in opentalon executor (install skill, show config, etc.) without calling the LLM. Enable it in config with github: "opentalon/opentalon-commands" and ref: "master"; see config.example.yaml and the plugin README.

Core Principles

Security First

Security is not an afterthought. OpenTalon is secure by default with a minimal attack surface. Plugins run as separate OS processes communicating over gRPC, so a compromised or misbehaving plugin can never access the core's memory or escalate privileges. Secrets are handled properly, inputs are validated at every boundary, and dependencies are kept lean and audited. No shortcuts.

graph LR
    User[User Message] --> Core[OpenTalon Core / LLM]
    Core -->|"conversation context only"| PluginA[Plugin A]
    Core -->|"conversation context only"| PluginB[Plugin B]
    PluginA -->|"result"| Core
    PluginB -->|"result"| Core
    PluginA x--x|"blocked"| PluginB
Loading
  • Plugins work strictly within their own scope — each plugin does its job and returns a result, nothing else
  • Plugins never talk to each other — no shared state, no event bus, no direct calls
  • A plugin cannot trigger another plugin — not via its response, not via prompt injection, not by any mechanism. Only the core/LLM decides what runs next
  • The LLM orchestrates everything — it decides which plugin to call, in what order, and routes results between them
  • Plugins only see what the core sends — conversation context and the specific task, nothing more

How isolation is enforced

Every plugin response passes through a guard pipeline before reaching the LLM:

flowchart TD
    LLM[LLM decides tool call] --> Validate[Validate call against registry]
    Validate --> Timeout["Set timeout (default 30s)"]
    Timeout --> Execute[Execute plugin via gRPC]
    Execute --> SizeCheck{Response within 64KB limit?}
    SizeCheck -->|No| Truncate[Truncate + add notice]
    SizeCheck -->|Yes| Sanitize[Strip forbidden patterns]
    Truncate --> Sanitize
    Sanitize --> ValidateResult{CallID matches? Fields valid?}
    ValidateResult -->|No| ErrorResult[Replace with error]
    ValidateResult -->|Yes| WrapResult["Wrap in [plugin_output] block"]
    ErrorResult --> FeedBack[Feed back to LLM as data]
    WrapResult --> FeedBack
Loading
Threat Guard
Plugin returns fake tool calls in its output Response sanitizer strips all tool-call patterns before the LLM sees them
Plugin crafts output to trick the LLM Output is wrapped in [plugin_output] blocks — the LLM is instructed to treat it as data only
Plugin tries to read another plugin's state State store enforces namespace isolation — pluginID is set by the core, not the plugin
Plugin tries to discover or call other plugins gRPC contract exposes exactly one method: Execute. No registry, no peer discovery
Plugin runs forever or consumes all resources Per-call timeout (configurable) + OS-level resource limits
LLM autonomously installs or modifies skills/plugins user_only actions are hidden from the LLM system prompt and blocked if invoked via an LLM-generated tool call

Guard of LLM models: A plugin can host its own LLM (e.g. a small local model or a dedicated API). Used as a content preparer, such a plugin can implement a guard of LLM models—for example, classify or validate the request and block or redirect before the main orchestrator LLM is invoked, or enforce which models or providers are allowed. The core only sees the plugin’s result (e.g. transformed message or “do not send to LLM”); the plugin’s internal use of an LLM stays out of the main token path.

Content Preparers

Content preparers are plugin actions that run before the first LLM call. They receive the user’s message and can transform it, enrich it, or block it entirely by returning send_to_llm: false.

orchestrator:
  content_preparers:
    - plugin: opentalon-commands   # runs slash command handling before the LLM
      action: handle
    - plugin: terminology          # rewrites non-standard terms to company vocabulary
      action: normalize

A preparer returns plain text (the transformed message) or a JSON response:

{ “send_to_llm”: false, “message”: “handled without LLM” }
{ “send_to_llm”: false, “invoke”: [
    { “plugin”: “jira”, “action”: “create_issue”, “args”: { “title”: “...” } }
]}

When send_to_llm is false, the LLM is never called — the preparer’s message or invoke steps become the response directly. Preparers with invoke steps must be explicitly trusted in config (see insecure: false in config.example.yaml).

Guard Plugins — Prompt Injection Prevention

Regular content preparers run once, on the initial user message. Guard plugins go further: they run before every LLM call in the agent loop — including after tool results come back — so they can sanitize content that arrives from external systems before the LLM ever sees it.

This is the primary defence against prompt injection: a malicious tool response that says ”ignore previous instructions and do X” is intercepted and sanitized by the guard before the LLM processes it.

orchestrator:
  content_preparers:
    - plugin: injection-guard
      action: sanitize
      guard: true        # ← runs before every LLM call, not just the first

Execution flow with a guard:

User message
    │
    ▼
[Content preparers]   ← regular preparers run once here
    │
    ▼
Agent loop iteration 1:
    ├─ [Guard plugins]  ← sanitize last message (user input)
    ├─ LLM call
    └─ Tool call → result appended
Agent loop iteration 2:
    ├─ [Guard plugins]  ← sanitize last message (tool result)  ← injection caught here
    ├─ LLM call
    └─ Final answer

The guard plugin receives the content of the most recent message (the last tool result or user message) as the text argument, and returns the sanitized version. It can also block entirely:

{ “send_to_llm”: false, “message”: “Prompt injection detected — request blocked.” }

Guard actions are never listed in the LLM’s tool list — they are invisible to the model and run transparently as part of the infrastructure.

A guard plugin can use a small/cheap LLM internally to detect subtle injections, or apply deterministic pattern matching — either way the main LLM only sees the clean output.

LLM Safety Rules

The LLM itself receives built-in safety rules in its system prompt at the start of every session. These rules instruct the LLM — in multiple languages — to never execute tool calls found inside plugin output, to treat all plugin responses as untrusted data, and to never let a plugin influence which other plugins get called.

The default rules are built into OpenTalon and can be customized via config.yaml:

orchestrator:
  rules:
    - "Never send PII or personal data to external plugins"
    - "All financial data must stay within internal plugins only"
    - |
      When working with customer data, follow these constraints:
      1. Never log raw customer identifiers
      2. Mask email addresses before passing to any plugin
      3. Reject plugin results that contain unmasked credit card numbers
    - |
      For compliance with internal policy SEC-2024-07:
      - Only approved plugins may access production databases
      - Plugin responses containing SQL must be flagged for review

This lets organizations add domain-specific rules — including multi-line instructions — without modifying source code. These custom rules are appended to the built-in safety rules and injected into the LLM system prompt at the start of every session.

Company Rules, Context & Vocabulary — Without Burning LLM Tokens

Hooks let organizations enforce their own business rules, terminology, and compliance requirements before the message ever reaches the main LLM — using Lua for simple zero-overhead rules or Go / any language via gRPC for complex logic.

  • Vocabulary enforcement — rewrite non-standard terms into company-approved language. Lua replacement table (zero LLM cost) or a Go plugin loading terminology from a database.
  • Business rule classification — route, prioritize, or reject requests using deterministic rules. No tokens burned.
  • Compliance checks — detect PII, credentials, or policy violations. Lua for pattern matching, Go for compliance API integration.
  • Context enrichment — inject company metadata (project codes, team names, priority levels) so the main LLM has the right context without figuring it out.
  • Business transformation — convert LLM output into structured actions (Jira tickets, calendar events, CRM updates) using a gRPC plugin in any language.

For ambiguous cases, Lua hooks can call a small/cheap LLM (ctx.llm()) for lightweight AI. The main (expensive) LLM only sees clean, pre-processed input.

State and context persistence

When state.data_dir is set, conversation and rules persist across restarts using SQLite (state.db). The app uses the pure-Go driver modernc.org/sqlite, so no system SQLite library is required—it’s a normal Go dependency and is compiled into the binary. General rules (shared) and per-actor rules (per user) are stored as memories so multiple users get shared context plus their own. The LLM receives general context (config rules, general stored rules, tools), user/actor context (that actor’s stored rules), and the session (conversation history). Sessions are one per channel/conversation or thread; optional summarization after N messages compresses history into a summary and keeps only the last few messages, so token usage stays bounded. Pipeline state is currently in-memory only — persistence is planned for Phase 4. See docs/design/channels.md (State and memory) and config.example.yaml (state.session) for details.

User message ──▶ Pre-hooks (Lua / Go / small LLM) ──▶ Planner ──▶ Main LLM ──▶ Post-hooks (Lua / Go) ──▶ Response
                  │  zero tokens for rules                │            │              │
                  │  cheap tokens for small LLM           │            │              │  enforce vocabulary
                  │  full power via gRPC plugins           │            │              │  compliance, transform
                                                          │            │
                                                   multi-step?         │
                                                    ├─ yes ──▶ Pipeline Executor ──▶ Results
                                                    └─ no  ──▶ Agent Loop ─────────┘

Stability

Thorough testing at every level — unit, integration, and end-to-end. Pull requests can only be merged with a fully green test suite, no exceptions — not even for project owners :) Zero tolerance for repeatable bugs. Predictable behavior under load, graceful degradation, and clear error reporting.

Customizability

Everything in OpenTalon is extensible and language-agnostic. Tool plugins, channel adapters, and processing hooks can all be written in Go, Python, Rust, or any language that speaks gRPC. For simple rules, an embedded Lua VM provides hot-reloadable scripts with zero deployment overhead. Companies can enforce their own business rules, vocabulary, and compliance policies using deterministic logic — without burning LLM tokens. See Extensibility below.

Maintainability

Clean architecture, idiomatic Go, and high code quality standards enforced by linters, formatters, and code review. The codebase is designed to be readable and approachable for new contributors.

Multi-Platform Deployment

First-class support for running anywhere:

  • Local — single binary, no external dependencies required to get started
  • VPS — lightweight deployment with systemd or supervisor
  • Docker — official container images
  • Kubernetes — Helm charts for production-grade deployments

Extensibility

OpenTalon is fully extensible. Everything is language-agnostic — plugins, channels, and hooks can be written in Go, Python, Rust, TypeScript, or any language that speaks gRPC. For lightweight scripting, an embedded Lua VM provides hot-reloadable hooks with zero deployment overhead.

flowchart TD
    subgraph external ["External (any language: Go, Python, Rust, etc.)"]
        ToolA["Tool Plugin"]
        ToolB["Tool Plugin"]
        ChA["Channel Plugin"]
        ChB["Channel Plugin"]
    end

    subgraph core [OpenTalon Core]
        PreHooks["Pre-hooks (Lua / gRPC)"]
        ChannelReg[Channel Registry]
        Orch[LLM Orchestrator]
        ToolReg[Tool Registry]
        PostHooks["Post-hooks (Lua / gRPC)"]
    end

    ChA <-->|"gRPC / HTTP / WS"| ChannelReg
    ChB <-->|"gRPC / HTTP / WS"| ChannelReg
    ChannelReg --> PreHooks
    PreHooks --> Orch
    Orch --> ToolReg
    ToolReg <-->|gRPC| ToolA
    ToolReg <-->|gRPC| ToolB
    Orch --> PostHooks
    PostHooks --> ChannelReg
Loading

There are three extension categories, all language-agnostic:

Category Purpose Interface Examples
Tool plugins Capabilities the LLM invokes gRPC (PluginService) GitLab, Jira, code search, CI/CD
Channel plugins I/O adapters for messaging platforms gRPC / HTTP / WebSocket (ChannelService) Slack, Teams, Telegram, WhatsApp, Discord
Hooks Pre/post processing pipeline Lua (embedded) or gRPC Vocabulary enforcement, compliance, classification

Tool Plugins (gRPC — any language)

For standalone capabilities the LLM calls: integrations, actions, data retrieval.

  • Language-agnostic — write in Go, Python, Rust, or any language that speaks gRPC (Go is the primary SDK)
  • Each plugin is a separate binary communicating over gRPC via a local socket
  • Process isolation — a crashing plugin cannot take down the core
  • Security boundary — strict protobuf contracts; plugins cannot access other plugins, the registry, or core internals
  • Discovery and lifecycle — registered via config or auto-discovered from a directory, health-checked, and restarted on failure
  • Same proven pattern behind Terraform, Vault, and Nomad
  • user_only actions — set user_only: true on any action in Capabilities() to hide it from the LLM and allow it only via direct user invocation (e.g. slash commands). The core enforces this: LLM-generated calls to user_only actions are rejected. Built-in example: /install skill is user_only so only the user can install skills, not the LLM.

Channel Plugins (gRPC / HTTP / WS — any language)

I/O adapters for messaging platforms. Written in any language, deployed as separate binaries/services.

  • Platform-agnostic — the core defines a generic ChannelService contract. Implementations for Slack, Teams, Telegram, WhatsApp, Discord, Jira, Matrix, etc. live in separate repositories
  • Five connection modes — auto-detected from the plugin URI scheme:
Format Mode Best for
./path/to/binary Binary Local dev, simple deployments
grpc://host:port Remote gRPC Kubernetes, cloud-native
docker://image:tag Docker Self-hosted with isolation
https://endpoint/path Webhook Serverless (Lambda, Cloud Functions)
wss://host/path WebSocket Real-time, lightweight

Hooks: Lua Scripting + gRPC

Pre/post processing hooks run before and after the main LLM. Two options:

  • Lua scripts (embedded) — hot-reloadable, sandboxed, zero deployment overhead. Ideal for simple rules, filters, and quick customizations. Can call a small/local LLM via ctx.llm() for lightweight AI tasks. See Lua scripts for a full hello-world example. Inspired by Nginx/OpenResty, Kong, and Redis.
  • gRPC hook plugins (any language) — for complex business logic that needs databases, APIs, or custom libraries. Same process isolation and language flexibility as tool plugins.

Extension Points

All three categories share the same set of extension points:

MCP (Model Context Protocol) Support

OpenTalon supports the Model Context Protocol (MCP), allowing it to connect to any MCP-compatible tool server alongside its native gRPC plugins.

The opentalon/mcp-plugin acts as an MCP bridge: it runs as a standard OpenTalon gRPC tool plugin and transparently proxies tool calls to one or more MCP servers over HTTP+SSE. From the core's perspective it is just another plugin; from the MCP server's perspective it is a standard MCP client.

OpenTalon Core  ──gRPC──▶  mcp-plugin  ──HTTP+SSE──▶  MCP Server A
                                        ──HTTP+SSE──▶  MCP Server B

Configure it like any other plugin:

plugins:
  mcp:
    enabled: true
    github: "opentalon/mcp-plugin"
    ref: "master"
    config:
      servers:
        - name: my-mcp-server
          url: "http://localhost:8080/sse"

Each tool exposed by the MCP servers is automatically registered in OpenTalon's tool registry and becomes callable by the LLM. All security guards (response sanitization, size limits, timeouts, namespace isolation) apply to MCP tool results exactly as they do to native gRPC plugins.

Developer Experience

  • Example: Hello World plugin — build your first tool plugin (hello→world + optional prompt fragment), then run OpenTalon with DeepSeek or any provider.
  • gRPC Plugin SDK — scaffolding CLI, example plugins, and integration test helpers. Works for tool plugins, channel plugins, and gRPC hooks.
  • Lua scriptsLua scripts guide with a hello-world example; API reference, example scripts, and a REPL for interactive testing

For the full architecture, see docs/design/plugins.md and docs/design/channels.md. For real-world workflow examples, see examples/.

Channel configuration example — all five modes side by side:

channels:
  my-slack:
    enabled: true
    plugin: "./plugins/opentalon-slack"                       # binary
    config:
      app_token: "${SLACK_APP_TOKEN}"
      bot_token: "${SLACK_BOT_TOKEN}"
  my-telegram:
    enabled: true
    plugin: "grpc://telegram-bot.internal:9001"               # remote gRPC
    config:
      bot_token: "${TELEGRAM_BOT_TOKEN}"
  my-teams:
    enabled: true
    plugin: "docker://ghcr.io/opentalon/plugin-teams:latest"  # docker
    config:
      tenant_id: "${TEAMS_TENANT_ID}"
  my-whatsapp:
    enabled: true
    plugin: "https://us-central1-proj.cloudfunctions.net/wa"  # webhook
    config:
      verify_token: "${WA_VERIFY_TOKEN}"
  my-custom:
    enabled: true
    plugin: "wss://custom-bridge.example.com/channel"         # websocket
    config:
      api_key: "${CUSTOM_API_KEY}"

The config block is opaque to the core — forwarded to the plugin without interpretation. Each plugin interprets its own config however it needs.

Built-in YAML Channels (no plugin binary needed)

For simple integrations like Telegram's HTTP long-polling API, you can define the channel entirely in YAML — no Go/gRPC plugin required. Configure the polling endpoint, response mapping, and reply endpoint in config, and OpenTalon handles the poll loop, cursor tracking, and message dispatch.

# channels/telegram-channel/channel.yaml
id: telegram
name: Telegram

inbound:
  polling:
    method: GET
    url: "https://api.telegram.org/bot{{env.TELEGRAM_BOT_TOKEN}}/getUpdates?timeout=30&offset={{self.poll_offset}}"
    interval: 1s
    result_path: result        # where the update array lives in the JSON response
    cursor_field: update_id    # tracked automatically; next poll uses max(update_id)+1

  event_path: "message"        # extract the message object from each update
  mapping:
    conversation_id: "chat.id"
    sender_id: "from.id"
    content: "text"

outbound:
  send:
    method: POST
    url: "https://api.telegram.org/bot{{env.TELEGRAM_BOT_TOKEN}}/sendMessage"
    headers:
      Content-Type: application/json
    body: '{"chat_id":"{{msg.conversation_id}}","text":"{{msg.content}}"}'

YAML channels support filtering (process_when, skip), content transforms (regex replace, trim), deduplication, and response chunking — all declarative, no code.

Smart Model Routing

OpenTalon includes a weighted smart router that automatically picks the best AI model for each task — optimizing for cost without sacrificing quality.

graph LR
    Request[Request] --> Classifier[Task Classifier]
    Classifier --> Router[Weighted Router]
    Router --> CheapModel["Cheap Model (weight: 90)"]
    Router --> MidModel["Mid Model (weight: 50)"]
    Router --> StrongModel["Strong Model (weight: 10)"]
    CheapModel --> Signal{User accepts?}
    Signal --> |Yes| Store[Affinity Store]
    Signal --> |No| MidModel
    Store --> |"learns over time"| Router
Loading

How it works

  1. Weights — each model has a weight (0–100). Cheaper models get higher weight and are tried first
  2. Auto-classification — incoming requests are categorized by heuristics (message length, code blocks, keywords, conversation depth)
  3. Escalation — if the user rejects a response (regenerates, says "try again", or thumbs-down), the system escalates to the next model by weight
  4. Learning — the affinity store records which model succeeded for which task type. Over time, the router learns: "code generation needs Sonnet, simple Q&A is fine on Haiku"
  5. User overrides — if you already know what you want, pin a model per request (--model), per session (/model), or per task type in config

Multi-Provider Support

OpenTalon supports multiple AI providers out of the box, with a unified configuration:

  • Built-in providers — Anthropic, OpenAI, Google, and more
  • Custom providers — any OpenAI-compatible or Anthropic-compatible endpoint (self-hosted, OVH, Ollama, vLLM, etc.)
  • Provider plugins — add new providers via the gRPC plugin system
  • Auth profile rotation — multiple API keys or OAuth tokens per provider, with automatic round-robin and cooldown on rate limits
  • Two-stage failover — first rotate credentials within a provider, then fall back to the next model in the chain. Exponential backoff on failures.

Getting started? See the Configuration Guide for step-by-step setup instructions. For the full architecture, see docs/design/providers.md.

Scheduler

OpenTalon includes a built-in scheduler for periodic background jobs. Jobs can be defined statically in config.yaml or created dynamically through conversation — the LLM proposes a schedule, the user confirms, and the job is persisted.

flowchart LR
    Scheduler["Scheduler (tick)"] --> Runner["Execute plugin action"]
    Runner --> Result["Result"]
    Result --> Notify["Notify channel (Slack, Teams, …)"]
    
    User["User via chat"] -->|"create / list / delete"| LLM
    LLM -->|"scheduler tool"| Scheduler
    Config["config.yaml"] -->|"static jobs"| Scheduler
Loading

Example: Monitor GitHub and notify Slack

scheduler:
  approvers: ["ops@company.com"]
  max_jobs_per_user: 5
  jobs:
    - name: github-status
      interval: 10m
      action: github.check_status
      args:
        org: "opentalon"
      notify_channel: slack-ops
    - name: deploy-digest
      interval: 24h
      action: github.deployment_summary
      args:
        repo: "opentalon/opentalon"
      notify_channel: slack-engineering

Every 10 minutes, the github plugin checks the organization's status and posts results to the slack-ops channel. A daily deployment digest goes to slack-engineering.

Dynamic jobs via conversation

Users can also create jobs by talking to the LLM:

User: "Watch the opentalon/opentalon repo for failed CI runs and let me know in #builds"

LLM: "I'll create a job that checks CI status every 20 minutes and notifies #builds. Should I go ahead?"

User: "Yes, but check every 15m"

LLM: "Done — created job ci-watch-opentalon running every 15m, notifying #builds."

Governance

  • Config-defined jobs are immutable — users cannot modify or remove them through conversation
  • Approvers — when configured, only designated users can create, update, or delete dynamic jobs
  • Per-user limitsmax_jobs_per_user prevents any single user from creating excessive jobs
  • Full CRUD — list, pause, resume, update, and delete jobs through the LLM or directly via the scheduler API

Pipeline Execution

When a user request involves multiple steps (e.g. "check the bug in AppSignal, create a Jira ticket, and open a merge request"), OpenTalon's pipeline planner decomposes it into a structured plan, asks for confirmation, and executes each step with built-in retry and error reporting.

flowchart LR
    User["User Message"] --> Planner["Planner (LLM)"]
    Planner -->|"multi-step"| Plan["Plan + Confirm"]
    Plan -->|"approved"| Executor["Pipeline Executor"]
    Executor --> Results["Results"]
    Planner -->|"single-step"| AgentLoop["Agent Loop"]
    AgentLoop --> Results
Loading

How it works

  1. Planner — a separate LLM call decomposes the user prompt into a DAG of steps with dependencies. If the prompt is a simple single-step request, the normal agent loop handles it (safe degradation).
  2. Confirmation — the plan is presented to the user via their channel (Slack, console, etc.). The user approves (y/yes) or rejects. Nothing executes without explicit approval.
  3. Executor — walks the step DAG in dependency order. Each step calls a plugin action via gRPC. Per-step retry with exponential backoff, per-step timeout, and fail-fast or continue-on-error behavior.
  4. Results — on completion (or failure), the user sees what succeeded, what failed, and how many retries were attempted. All tool calls and results are recorded in the session history.

Example conversation

User: "Check bug #4521 in AppSignal, then create a Jira ticket and open a GitLab MR with the fix"

OpenTalon:

I've created a plan with the following steps:

1. Check bug in AppSignal
   Action: appsignal.get_error (error_id=4521)
2. Create Jira bug ticket
   Action: jira.create_issue
   Depends on: 1
3. Create MR with fix
   Action: gitlab.create_mr
   Depends on: 1, 2

Proceed? (y)es / (n)o

User: "y"

OpenTalon: "Pipeline complete — 3/3 steps succeeded."

Configuration

orchestrator:
  pipeline:
    enabled: true          # default false
    max_step_retries: 3    # retries per step before giving up (default 3)
    step_timeout: "60s"    # per-step timeout as Go duration (default "60s")

Concurrency

By default, OpenTalon processes one session at a time (max_concurrent_sessions: 1). This matches the original sequential behaviour and is the safe default for most deployments. Enable concurrent session processing by raising the limit:

orchestrator:
  max_concurrent_sessions: 5   # up to 5 sessions run in parallel (default: 1)

How it works:

  • Different sessions run in parallel — up to the configured limit. Session A no longer waits for Session B to finish.
  • Same session is always serialized — a second message to the same session waits for the first to complete, regardless of the limit. This preserves conversation ordering.
  • Backpressure is built-in — when the limit is reached, new requests wait until a slot is free (or their context is cancelled).
max_concurrent_sessions: 3

Session A ──────────────────► reply A   ┐
Session B ──────────────────► reply B   ├─ run in parallel
Session C ──────────────────► reply C   ┘
Session D ···················► (waits for A, B, or C to finish)

Same session:
Session A msg1 ──────────────► reply 1
Session A msg2 ···············► (waits for msg1 to finish) ──► reply 2

Set max_concurrent_sessions to match your LLM provider's rate limits and expected load. A value of 1 (default) gives the original sequential behaviour with no behaviour change needed for existing deployments.

Debugging

Set LOG_LEVEL=debug to see pipeline decisions, planner LLM calls, step execution, and retry attempts — all prefixed with [pipeline].

When debug is enabled, each conversation also writes to its own log file under {data_dir}/logs/ (default ~/.opentalon/logs/). Files are named by timestamp and the first message, e.g. 20260318_093609_wazzup.log, so you can quickly find and read logs for a specific chat. Non-ASCII first messages (emoji, cyrillic) use a short hash instead. Override the directory with log.dir:

log:
  file: ~/.opentalon/opentalon.log   # global log file (all sessions)
  dir: ~/.opentalon/logs             # per-session log directory (optional, defaults to {data_dir}/logs)

Log files older than 7 days are cleaned up automatically on startup.

Current limitations (Phase 1)

  • In-memory only — pipeline state is not persisted; a process restart loses pending/running pipelines (persistence planned for Phase 4)
  • No step output templating — template references like {{steps.1.output.id}} are passed literally to plugins (planned for Phase 3)
  • Sequential execution only — steps with independent dependencies run one at a time (parallel execution planned for Phase 3)
  • LLM quality dependent — weaker models may return single-step plans for multi-step requests, causing fallback to the agent loop (expected safe degradation)
  • No recovery advisor — failed steps are retried as-is without LLM-assisted diagnosis (planned for Phase 2)

For the full roadmap (recovery advisor, replan, parallel execution, persistence), see docs/design/pipeline.md.

Build locally with plugins

Prerequisites: Go 1.24+, git.

Quick start (recommended)

git clone https://github.com/opentalon/opentalon.git
cd opentalon
cp config.example.yaml config.yaml
# Set your API key (DeepSeek, OpenAI, or any compatible provider):
export DEEPSEEK_API_KEY="your-key"

make build setup   # build core binary + clone & build hello-world plugin and console channel
./opentalon -config config.yaml

make setup clones opentalon/console-channel into channels/ and opentalon/hellow-world-plugin into plugins/, then builds both. The binaries land at channels/console-channel/console and plugins/hellow-world-plugin/hello-world-plugin — matching the paths in config.example.yaml.

Other useful Make targets:

Target What it does
make build Build the core binary
make setup Clone and build the hello-world plugin and console channel
make plugin Clone and build only the hello-world plugin
make channel Clone and build only the console channel
make run Build + setup + start OpenTalon
make test Run tests with race detector
make lint Run golangci-lint
make all deps + build + test + lint
make clean Remove built binaries

Alternative: GitHub auto-fetch (bundler)

Instead of building locally, you can let OpenTalon fetch and build plugins/channels on first run. In config.yaml, replace plugin: with github: and ref::

channels:
  console:
    enabled: true
    github: "opentalon/console-channel"
    ref: "master"
    config: {}

plugins:
  hello-world:
    enabled: true
    github: "opentalon/hellow-world-plugin"
    ref: "master"
    config: {}

The first run resolves the refs, clones and builds, and writes channels.lock and plugins.lock under state.data_dir (default ~/.opentalon). Later runs reuse the locked versions until you change ref or delete the lock entries.

Reusable skills from OpenClaw

You can add request packages — skill-style API calls with no compiled plugin. The core runs HTTP requests from templates ({{env.VAR}}, {{args.param}}), with optional guardrails (required_env). This is a good fit for OpenClaw/ClawHub-style skills: each skill is a directory with a SKILL.md (and optionally request.yaml), and OpenTalon can download skills by name so you only specify the skill name in config.

Download skills by name — set a default repo and list the skill names you want. The core clones the repo once (or one repo per skill if you override), parses each skill’s SKILL.md, and registers them as tools. No build step.

request_packages:
  default_skill_github: openclaw/skills    # one repo, many skill subdirs
  default_skill_ref: main
  skills:
    - jira-create-issue
    - slack-send

For a skill from a different repo, use the object form:

request_packages:
  skills:
    - name: my-custom-skill
      github: myorg/my-skills
      ref: v1

Downloaded skills are stored under state.data_dir and pinned in skills.lock (same idea as plugins.lock). You can also use a local directory of skills with skills_path, or define inline request packages in config — see config.example.yaml for the full request_packages options.

Contributing

We welcome contributions of all kinds — bug reports, feature requests, documentation improvements, and code.

  1. Report issues — found a bug or have an idea? Open an issue with a clear description and steps to reproduce
  2. Submit pull requests — fork the repo, create a feature branch, and open a PR against master. Keep PRs focused on a single change
  3. Write tests — every PR must include tests. The CI pipeline runs go test -race ./... and golangci-lint — both must pass before merging
  4. Follow conventions — idiomatic Go, gofmt-formatted, meaningful commit messages. Read the existing code to match the style
  5. Discuss first — for large changes or new features, open an issue to discuss the approach before writing code

All contributions are subject to the Apache 2.0 License.

License

OpenTalon is licensed under the Apache License 2.0.