How duckbugio/flock works
1. Monorepo split into platform-agnostic core and channel adapters.
The central architecture is in core/, which contains the Claude-driven agent orchestration, workspace management, polling, git/PR integration, voice handling, and shared chat logic. adapters/telegram/ and adapters/vk/ are thin transport-specific front ends that translate a chat platform’s events into the core’s internal chat/service model. The repo is set up so new transports can be added under adapters/<name>/ without changing the core.
2. Two runnable bot entrypoints.
cmd/flock-telegram and cmd/duck-vk are the deployable binaries. Each wires configuration, the adapter, and the shared core together. The Telegram path is the primary product and is packaged with Docker, Compose, and Ansible deployment assets under adapters/telegram/deploy/.
3. Core control plane: chat service plus orchestration pipeline.
core/chat/ is the main request lifecycle: it accepts incoming chat events, applies guardrails, manages the outbox/progress/nudge behavior, chunks and routes messages, and coordinates agent work. core/dispatch/ and core/poller/ drive event routing and background polling loops, while core/session/ keeps per-chat state. This is the boundary where a human message becomes either a normal answer or a multi-step development run.
4. Claude Code execution is isolated behind a dedicated runner layer.
core/claude/ wraps the Claude Code CLI, including streaming/tailing, JSONL decoding, MCP support, and tests with fake transcripts. This layer is the bridge from orchestration into actual model execution. The README’s “Claude dev team” is implemented as subagents in core/agents/, with the pipeline roles planner → coder → tester → reviewer → arbiter.
5. Per-chat workspace isolation is a first-class subsystem.
core/workspace/ creates and manages isolated directories per chat, matching the repo’s model of /workspace/chat_<id>. The bot uses these workspaces to ensure that different chats cannot see each other’s files and can run in parallel up to a concurrency limit. core/gitsetup/ complements this by preparing repos/branches for agent work and PR creation.
6. Transport adapters focus on message shape, rich content, and platform-specific constraints.
adapters/telegram/ contains Telegram-specific command handling, message formatting, rich text transport, upload/voice helpers, and the bot bootstrap. adapters/vk/ contains the equivalent VK logic: long polling, API calls, mention detection, payload handling, and media upload. The core chat layer stays transport-neutral; each adapter maps platform events into the core and maps responses back into the platform’s formatting rules.
7. Media and voice are separate processing paths, not just text extensions.
core/voice/ handles transcription and voice-provider abstraction, with adapters/telegram/voice.go and adapters/vk/voice.go integrating platform uploads/attachments. This means voice messages enter the system through a dedicated decode/transcribe path before they become normal chat commands or prompts. The README notes multiple providers, including remote APIs and local mode.
8. Git host integration is asynchronous and poll-based.
The system supports Gitea/GitHub/GitLab-style flows through core/ghstar/, core/poller/, and likely the git-related utilities around the bot’s run lifecycle. A key design choice is that PR review comments are handled by outbound polling instead of inbound webhooks, so the bot can operate even when the git host cannot reach it. This matches the architecture’s “chat triggers work, poller closes the loop” model.
9. Guardrails and cost/rate controls sit inside the core, not the adapter.
core/ratelimit/, core/cost/, core/pending/, core/nudge/, and core/chat/guards.go enforce safety, throttling, and run bookkeeping. These are the boundaries that keep the agent from looping forever, spamming replies, or running uncontrolled. The arbiter role in the team is the semantic loop-breaker; these packages are the operational guardrails.
10. Shared internal utilities support safe file and config handling.
internal/atomicfile/ provides atomic writes, internal/fsutil/ handles upload/file utilities, and internal/config/ centralizes environment/config parsing. These are low-level support packages used across the bot and deployment paths to keep state changes safe and consistent.
11. Deployment is image-first, with optional orchestration sidecars.
The Telegram adapter ships with its own Dockerfile, docker-compose.yml, and Ansible role/playbook templates. The default deployment runs as a prebuilt container, with optional sidecars for Docker-in-Docker CI tooling and Caddy for webhook/TLS ingress. This makes runtime packaging part of the adapter boundary rather than the core application logic.
12. Testing is broad and component-level.
Most subsystems have focused unit tests beside the code, and core/claude/ includes integration-style fixtures for CLI transcript decoding. That suggests the architecture is built around deterministic orchestration and adapter translation, with tests validating message routing, workspace behavior, and external integration wrappers rather than only end-to-end bot runs.
13. Conceptual data flow for diagramming.
A user message enters a transport adapter, is normalized into a core chat event, passes through session/guard/rate-limit logic, and is either answered directly or routed into the Claude team pipeline. If it becomes a development task, the core creates/uses an isolated workspace, runs Claude Code subagents, writes files, tests, and git operations, then posts progress back through the adapter. Background pollers later bring PR review comments back into the originating chat.
14. Primary architectural boundaries to draw.
The most important boundaries are: transport vs. core, chat orchestration vs. Claude execution, per-chat workspace isolation vs. shared deployment secrets, and synchronous chat handling vs. asynchronous polling/background reconciliation. These are the lines that define how the system stays multi-tenant, multi-transport, and safe to run on one server.
Main entry points: service.go Chat service · telegram/bot.go Telegram bot · vk/bot.go VK bot · voice.go Voice core
Components 22
Binaries
Deployable entrypoints for the two bot runtimes.
- flock-telegram · Primary Telegram bot executable wiring config, adapter, and core.
cmd/flock-telegram/main.go - duck-vk · VK bot executable wiring config, adapter, and core.
cmd/duck-vk/main.go
Adapters
Transport-specific front ends for chat platforms and deployment packaging.
- Telegram bot · Telegram command handling, message routing, and bot lifecycle.
adapters/telegram/bot.go - Rich transport · Telegram-specific rich text, wire format, and content mapping.
adapters/telegram/richtransport.go - Telegram voice · Telegram upload and voice handling before handing off to core voice logic.
adapters/telegram/voice.go - Telegram deploy · Docker, Compose, Ansible, and ingress templates for Telegram deployment.
adapters/telegram/deploy/playbook.yml - VK bot · VK long-poll bot lifecycle and event handling.
adapters/vk/bot.go - VK API · VK API integration for messaging, uploads, and polling.
adapters/vk/api.go - VK voice · VK upload and voice handling before handoff into core voice logic.
adapters/vk/voice.go
Core
Platform-neutral orchestration, agent execution, and shared bot logic.
- Chat service · Main request lifecycle: guardrails, outbox, progress, chunking, and routing.
core/chat/service.go - Dispatch · Routes incoming chat events into the core service pipeline.
core/dispatch/dispatch.go - Session state · Tracks conversation state and chat-local context.
core/session/session.go - Claude runner · Wraps Claude Code CLI execution, streaming, decoding, and MCP support.
core/claude/runner.go - Agent team · Planner, coder, tester, reviewer, and arbiter roles for development runs.
core/agents/planner.md - Workspace · Creates isolated per-chat workspaces for parallel agent runs.
core/workspace/workspace.go - Git setup · Prepares repositories, branches, and PR-friendly worktrees for agent work.
core/gitsetup/gitsetup.go - Poller · Asynchronous reconciliation loop for git-host events and review comments.
core/poller/poller.go - Git host · GitHub/Gitea/GitLab-style integration for PR and review workflows.
core/ghstar/ghstar.go - Voice core · Platform-neutral voice abstraction and transcription providers.
core/voice/voice.go
Support
Low-level shared utilities used across the repo.
- Config · Shared configuration and environment parsing.
internal/config/config.go - FS utils · Shared upload and file helpers.
internal/fsutil/upload.go - Atomic file · Atomic write helper for durable state changes.
internal/atomicfile/atomicfile.go
Connections 32
- flock-telegram → Telegram bot: boots · The Telegram binary initializes the Telegram adapter.
- flock-telegram → Chat service: wires · Connects Telegram events into the shared chat service.
- flock-telegram → Config: loads · Reads environment and runtime configuration.
- duck-vk → VK bot: boots · The VK binary initializes the VK adapter.
- duck-vk → Chat service: wires · Connects VK events into the shared chat service.
- duck-vk → Config: loads · Reads environment and runtime configuration.
- Telegram bot → Rich transport: formats · Maps core responses to Telegram rich content.
- Telegram bot → Telegram voice: handles media · Routes Telegram voice and uploads into core voice handling.
- Telegram bot → Chat service: sends events · Normalizes Telegram messages into core chat events.
- Telegram bot → FS utils: uploads · Uses shared file helpers for platform attachments.
- Telegram voice → Voice core: transcribes · Bridges Telegram voice payloads into core voice processing.
- VK bot → VK API: calls · Uses VK API and long-poll plumbing.
- VK bot → VK voice: handles media · Routes VK voice and uploads into core voice handling.
- VK bot → Chat service: sends events · Normalizes VK messages into core chat events.
- VK voice → Voice core: transcribes · Bridges VK voice payloads into core voice processing.
- Chat service → Session state: tracks · Maintains per-chat state across turns.
- Chat service → Dispatch: routes · Dispatches chat events through the orchestration pipeline.
- Chat service → Workspace: isolates · Creates or reuses per-chat workspaces for agent runs.
- Chat service → Claude runner: executes · Invokes Claude Code for model-driven work.
- Chat service → Agent team: coordinates · Selects and sequences planner/coder/tester/reviewer/arbiter roles.
- Chat service → Git setup: prepares repos · Sets up git state for development tasks and PRs.
- Chat service → Voice core: decodes voice · Converts voice input into chat prompts.
- Chat service → Atomic file: writes safely · Persists state and artifacts with atomic updates.
- Poller → Git host: reconciles · Polls git-host state and feeds updates back into the bot.
- Poller → Chat service: feeds updates · Reinjects asynchronous git-host events into chat flows.
- Git setup → Workspace: uses · Prepares repo work inside isolated workspaces.
- Git setup → Git host: syncs · Coordinates git-host metadata for PR workflows.
- Claude runner → Agent team: runs roles · Executes the subagent workflow through Claude Code.
- Claude runner → Workspace: reads/writes · Operates against the per-chat workspace filesystem.
- Voice core → FS utils: uses · Shares file and upload utilities for voice handling.
- Telegram deploy → Telegram bot: packages · Deployment assets ship the Telegram adapter and binary.
- Config → Chat service: configures · Supplies core runtime settings.