Releases: kOlapsis/herald
v0.1.2
This release focuses on stability and architecture. Claude Chat no longer burns through rate limits polling every few seconds, and Herald's executor layer is now ready for alternative CLI backends.
Highlights
- Polling guidance — Tool descriptions and responses now instruct Claude Chat to use long-polling (
wait_seconds=30), drastically reducing unnecessary API calls. - Executor registry — The executor layer is now pluggable. Claude Code is registered as a backend via
init(), and new CLI backends can be added without touching existing code. - Task context tracking — Tasks now carry a human-readable
contextfield, making it easy to understand why a task was launched when reviewing history across sessions.
What's New
Reduced Polling Frequency
Claude Chat was calling check_task every few seconds, quickly exhausting rate limits and wasting tokens. Three changes fix this:
- Tool descriptions for
start_taskandcheck_tasknow explicitly recommendwait_seconds=30long-polling. - Response text from both handlers includes clear guidance: "Do NOT call check_task more than once every 30 seconds."
longPollMaxWaitincreased from 30 to 60 seconds, allowing Claude Chat to wait longer per request.
Combined with the rate limit increase (see Fixes), polling-related throttling should be eliminated.
Executor Registry
The executor layer has been refactored into a pluggable registry pattern:
Register/Get/Available— Factory-based registration. Backends register themselves viainit().- Claude Code moved to
internal/executor/claude/— Auto-registered sub-package, cleanly separated from the registry. Capabilitiesstruct — Each executor declares what it supports (sessions, model selection, tool lists, dry run, streaming), so handlers can adapt.GracefulKillextracted — Shared process termination logic inkill.go.- Config field — New
executorfield inExecutionConfig(defaults to"claude-code"for backward compatibility).
Zero breaking changes on the MCP API or YAML configuration.
Task Context Field
A new context parameter on start_task lets Claude Chat attach a human-readable description of why a task was launched:
start_task(prompt="...", context="User asked to fix the login bug from mobile")
The context appears in check_task, list_tasks, and get_result responses, making task history meaningful across sessions.
Fixes
- Rate limits increased — Default bumped from 100 req/min (burst 30) to 600 req/min (burst 200). Claude Chat sends many parallel MCP requests that exhausted the old limits.
- OAuth authorize URL — Fixed incorrect redirect in the authorization flow.
- Security findings — Resolved remaining gosec and gocritic findings in
main.go(HTTP server timeouts, error handling, if-else to switch).
Upgrade
# Binary upgrade
curl -fsSL https://raw.githubusercontent.com/btouchard/herald/main/install.sh | sh
# Or rebuild from source
git pull && make buildNo configuration changes required. All new defaults are backward compatible.
What's Next (v0.2)
- Shared memory — bidirectional context between Claude Chat and Claude Code
- Model templates per task type (e.g. review → opus, test → sonnet)
License: AGPL-3.0
Documentation: btouchard.github.io/herald
Built by: Benjamin Touchard
If Herald saves you time, leave a star. It helps others find the project.
v0.1.1
This release makes Herald dramatically easier to set up. No more Traefik, Caddy, or DNS configuration — just plug in your ngrok token and go.
Highlights
- ngrok tunnel built-in — One config flag and Herald is accessible over HTTPS. No reverse proxy, no TLS certificates, no DNS records.
- Interactive install wizard — The install script now walks you through port, exposure method, and project setup. Generates a complete
herald.yaml. - Graceful shutdown — Long-running SSE connections no longer block server shutdown for 10+ seconds.
What's New
ngrok Tunnel Integration
Herald can now expose itself over HTTPS instantly via ngrok, without any reverse proxy setup:
tunnel:
enabled: true
provider: "ngrok"
authtoken: "2abc..." # or set HERALD_NGROK_AUTHTOKEN env var
# domain: "my-herald.ngrok-free.app" # optional: fixed domain (paid plans)Run herald serve and the tunnel URL appears in the startup banner — paste it into Claude Chat and you're connected. Free ngrok plans work fine.
The tunnel starts before OAuth metadata is served, so the public URL is always correct for Custom Connector discovery.
Install Script Improvements
--localflag — Install from the localbin/directory instead of downloading from GitHub. Useful for testing.- Setup wizard — Interactive guided configuration: port, exposure method (ngrok / domain / local), and project setup.
- Config backup — If a config file already exists, the wizard backs it up with a timestamp before overwriting.
Fixes
- Graceful shutdown — SSE connections (MCP streaming) no longer cause a
context deadline exceedederror on Ctrl+C. Herald force-closes remaining connections after a 5-second grace period. - OAuth redirect URI — Added
https://claude.ai/api/mcp/auth_callbackto the default allowed redirect URIs. This is the URI Claude.ai actually sends during Custom Connector authentication. - Startup banner — Now displays the full MCP URL (e.g.
https://xxx.ngrok-free.app/mcp) ready to copy-paste into Claude Chat. No more forgetting the/mcpsuffix. - Tunnel error messages — Common ngrok errors (invalid token, domain in use, session limit) now show actionable messages with remediation steps instead of raw error codes.
- Executor pipe draining — Fixed a race condition where stdout/stderr pipes were not fully drained before calling
Wait(), which could lose output on fast-completing tasks. - Security findings — Resolved all gosec and gocritic findings.
Upgrade
# Binary upgrade
curl -fsSL https://raw.githubusercontent.com/btouchard/herald/main/install.sh | sh
# Or rebuild from source
git pull && make buildIf you already have a herald.yaml, add the new redirect URI to your config:
auth:
redirect_uris:
- "https://claude.ai/oauth/callback"
- "https://claude.ai/api/oauth/callback"
- "https://claude.ai/api/mcp/auth_callback" # ← add thisOr remove the redirect_uris section entirely to use the new defaults.
What's Next (v0.2)
- Shared memory — bidirectional context between Claude Chat and Claude Code
- Model templates per task type (e.g. review → opus, test → sonnet)
License: AGPL-3.0
Documentation: btouchard.github.io/herald
Built by: Benjamin Touchard
If Herald saves you time, leave a star. It helps others find the project.
v0.1.0
The first public release of Herald, a self-hosted MCP server that bridges Claude Chat to Claude Code using Anthropic's official [Custom Connectors](https://support.claude.com/en/articles/11503834-building-custom-connectors-via-remote-mcp-servers) protocol.
One Go binary. Zero hacks. Your code never leaves your machine.
Highlights
- Native MCP bridge — Claude Chat discovers Herald's 10 tools automatically via Streamable HTTP. No wrappers, no proxies, no unofficial APIs.
- Bidirectional — Claude Chat dispatches tasks to Claude Code, and Claude Code can push sessions back to Herald via
herald_pushfor remote continuation. - Single binary, zero CGO — ~15MB executable. Cross-compiles to Linux, macOS, Windows, ARM. No Docker required.
- 6 dependencies — chi, mcp-go, modernc/sqlite, uuid, yaml, testify. That's it.
Features
Core
- 10 MCP tools:
start_task,check_task,get_result,list_tasks,cancel_task,get_diff,list_projects,read_file,herald_push,get_logs - Async task execution — Start tasks, check progress, get results. Claude Code runs in the background.
- Git branch isolation — Each task runs on its own branch. Main stays untouched.
- Session resumption — Multi-turn Claude Code conversations. Pick up where you left off.
- Bidirectional bridge —
herald_pushlets Claude Code push session context to Herald for remote monitoring and continuation from another device. - Linked sessions — Sessions pushed via
herald_pushappear aslinkedtasks, listable and resumable from Claude Chat. - Configurable model per task — Choose the model for each task (
modelparameter onstart_task), defaults to Sonnet for cost efficiency.
Multi-Project
- Multiple projects with independent settings, paths, and tool restrictions.
- Per-project allowed tools — Full sandboxing. No blanket
--dangerously-skip-permissions.
Operations
- MCP push notifications — Task lifecycle events pushed directly to Claude Chat via SSE. No polling needed.
- Long-polling on
check_task— Returns only on status change, not on every progress update. - Duration estimation on
start_task— Provides an estimated completion time based on task parameters. - SQLite persistence — Tasks survive server restarts. Full history, searchable.
- Structured logging —
log/slogwith text (stdout) and JSON (file) outputs.
Auth & Security
- OAuth 2.1 + PKCE — Every MCP request requires a valid Bearer token. Authorization code flow with mandatory S256 PKCE.
- Auto-generated secrets — Zero-config auth setup. Secret persisted to disk, displayed at startup.
herald rotate-secret— Rotate the client secret and invalidate all sessions.- Constant-time secret comparison — Client secret hashed at rest with SHA-256.
- Redirect URI validation — Prevents open redirect attacks.
- Per-token and per-IP rate limiting — Token bucket algorithm, configurable (default: 200 req/min).
- Max concurrent task enforcement — Prevents resource exhaustion.
- Timeout validation and clamping — Defense-in-depth at handler and task manager layers.
- Path traversal protection — All file operations validated against project root. Symlink escapes blocked.
- Security headers on all responses.
Deployment
herald serve— Start the server with optional--configflag.herald check— Validate configuration without starting.herald health— Check if the server is running (for Docker HEALTHCHECK).- Dockerfile — Multi-stage build (Go 1.26 → scratch).
- docker-compose.yml — Minimal deployment with Traefik.
- Install script —
curl -fsSL https://raw.githubusercontent.com/btouchard/herald/main/install.sh | sh
Installation
# Binary install
curl -fsSL https://raw.githubusercontent.com/btouchard/herald/main/install.sh | sh
# Or build from source (requires Go 1.26+)
git clone https://github.com/btouchard/herald.git
cd herald && make buildQuick Start
mkdir -p ~/.config/herald
cp configs/herald.example.yaml ~/.config/herald/herald.yaml
# Edit with your domain and projects
herald serve
# Client secret is displayed in the console — use it to configure Claude ChatThen in Claude Chat: Settings → Custom Connectors → Add https://herald.yourdomain.com/mcp
What's Next (v0.2)
- Shared memory — bidirectional context between Claude Chat and Claude Code
- Model templates per task type (e.g. review → opus, test → sonnet)
License: AGPL-3.0
Documentation: [btouchard.github.io/herald](https://btouchard.github.io/herald/)
Built by: [Benjamin Touchard](https://kolapsis.com)
If Herald saves you time, [leave a star](https://github.com/btouchard/herald). It helps others find the project.