← Blog

An Autonomous Software Development Pipeline Managed via Telegram

Hermes Agent + Kanban + OpenCode: β€œJust talk, let it handle the rest”

One-line summary: I send a message on Telegram β†’ the project is registered/cloned β†’ a kanban card is created β†’ an AI worker writes the code β†’ an independent AI reviewer inspects it β†’ if all gates pass, it squash-merges automatically β†’ DNS & deploy pipeline runs. I only interact via Telegram; my phone only buzzes with a 🚧 alert if something gets blocked or needs human decision.

In this post, I break down the end-to-end autonomous development pipeline I built for myself on a single VPS β€” complete with custom skills, MCPs, automation scripts, and real production learnings.


1. The Big Picture

Architecture Overview

Core design principle: The orchestrator I talk to (my main Hermes session) never writes code directly. The code is written by a dedicated worker agent, and that code is reviewed by a completely separate agent running in a fresh context. The golden rule: No agent is ever allowed to review its own work.


2. Layers & Components

LayerToolRole
InterfaceTelegramMy single entry point. Commands go in here, status alerts (βœ…/🚧) come back here.
OrchestratorHermes Agent (coder profile)Intent-to-task translation, project registry, dispatcher, and escalation management.
Task QueueHermes KanbanOne board per project, card lifecycle management, worker spawning, and event logging.
ImplementationOpenCode CLI (+ oh-my-opencode-slim)The tool writing the actual code; spawns sub-agents via delegate_task.
Alternative WorkersClaude Code / Codex CLIDrop-in alternative worker engines (skills are ready).
Reviewmr-review-merge skillIndependent reviewer + fixer agents with strict gating policies.
Git & Hygienegh CLI + agent-git-workflowIsolated git worktrees, branch hygiene, READY MRs, and squash merges.
Registryprojects.yamlSingle source of truth: slug β†’ repo path, GitHub slug, and deployment metadata.
CLI Scriptsbin/project-{register,task,list,deploy}Ergonomic wrapper scripts so the orchestrator doesn’t have to fiddle with repetitive commands.
Deploy LayerDokploy (VPS) + Cloudflarenixpacks builds, Traefik (80/443), Let’s Encrypt SSL, and auto-deploy on git push.
MCPscloudflare-api (remote), dokploy (stdio)Tool servers powering DNS and container deployment automation.

Skill Chain (Auto-Injected Per Task)

project-task
 β”œβ”€β”€ agent-git-workflow      β†’ worktree, branch, commit, and push discipline
 β”œβ”€β”€ opencode                β†’ code implementation delegation
 β”œβ”€β”€ github-pr-workflow      β†’ PR lifecycle, check, and merge flow
 └── (auto-injected) kanban-worker β†’ card lifecycle and Telegram notification hooks
Review Stage:
 └── mr-review-merge         β†’ reviewer/fixer spawning, gate policies, and squash merge

3. Directory Layout on My VPS

/opt/data/
β”œβ”€β”€ workspace/
β”‚   β”œβ”€β”€ projects.yaml            ← registry (single source of truth for all projects)
β”‚   β”œβ”€β”€ bin/
β”‚   β”‚   β”œβ”€β”€ project-register     ← add/create repo + kanban board + AGENTS.md
β”‚   β”‚   β”œβ”€β”€ project-task         ← dispatch coding task to board with required skill set
β”‚   β”‚   β”œβ”€β”€ project-list         ← project overview & board summary
β”‚   β”‚   └── project-deploy       ← DNS β†’ AGENTS.md β†’ Dokploy (strict sequence)
β”‚   └── repos/<slug>/            ← canonical checkouts (main branch is always pristine)
β”œβ”€β”€ .worktrees/t_<task_id>/      ← per-task isolated git worktrees
β”œβ”€β”€ opencode-xdg/config/opencode/opencode.jsonc   ← OpenCode & MCP configurations
β”œβ”€β”€ profiles/coder/              ← my Hermes profile: skills, .env, persistent memory
└── tmp/                         ← throwaway clones used by reviewer and fixer agents

⚠️ Critical pitfall: I NEVER set default_workdir on kanban boards. When running worktree-based tasks, the dispatcher resolves the workspace dynamically. Setting a static path collapses all concurrent tasks into a single checkout, causing collisions.


4. Flow A β€” Project Onboarding

Trigger: β€œAdd project X: ” (or just the project name to bootstrap a clean private repository from scratch).

Project Onboarding

I treat AGENTS.md as the constitution of each project: build, test, and lint commands, along with the Definition of Done (DoD), live there. If a newly registered repository lacks this file, the very first task analyzes the stack and writes a real AGENTS.md. Every subsequent worker and reviewer reads their guidelines directly from it.


5. Flow B β€” Task Creation & Autonomous Execution

Trigger: β€œIn project X, do this: …”

The single big task rule: No matter how complex a feature is, I always open a single card and explicitly forbid the worker from decomposing it in the task prompt. In practice, a few completely finished cards outperform dozens of half-baked subtasks every time.

Task Creation &#x26; Execution

While running, the kanban card transitions from todo β†’ running. Because each project’s board dispatches independently, I can develop multiple projects concurrently without blocking queues.


6. Flow C β€” Review & Merge Pipeline (The Heart of the System)

Once the worker opens an MR, it doesn’t sit around waiting for me to review it; the review pipeline kicks in immediately. Both sides operate with fresh context: The author cannot review its own code, and the fixer agent focuses on resolving feedback without ego or defending initial choices.

Review &#x26; Merge Pipeline

My Quality Gates:

GateTypePassing ConditionFailure Outcome
G1 VerdictHardapprove (0 critical issues, 0 warnings)Fix turn starts (max 2 turns). If unresolved, escalates to me. Never bypassed.
G2 TestsHardtests.failed = 0 (or test suite not applicable)Escalates. Faking test results is strictly forbidden.
G4 PathsHardProtected paths (.env, .github/*, lockfiles, etc.) untouchedEscalates

(Note: I completely removed the initial diff-size/line-count gate from the current pipeline. When developing an entire mini-game or major feature in a single card, large diffs are completely normal. As long as tests pass, verdict is clean, and protected paths are untouched, it merges regardless of line count.)

The reviewer leaves a COMMENT-type review on GitHub (since self-approval with a single personal access token is blocked by GitHub’s policy) β€” the merge decision is enforced by the pipeline itself. Reviewers and fixers never work in canonical checkouts; they use throwaway clones in /tmp.

If I jump in and manually merge a PR on GitHub while the pipeline is running, the system handles it gracefully: stranded fix commits are cherry-picked into a fresh MR.


7. Card Lifecycle

Card Lifecycle

Telegram escalation format (plain text): Task summary + MR link + test results + what is expected from me + one-tap unblock/close command. No news means everything is progressing smoothly in the background; I don’t need to poll or babysit.


8. Flow D β€” Deployment (Rule: DNS First, Dokploy Second)

Deploy Flow

  • DNS-only (proxied=false) by default: I keep Cloudflare proxy disabled so Let’s Encrypt HTTP-01 challenges reach the VPS Traefik instance directly.
  • Onboarding an empty repository sets up DNS, board, and AGENTS.md in seconds; the Dokploy container binding takes a single command after the first MR merges.
  • Deployment parameters are saved in projects.yaml under deploy: (domain, port, app ID), making subsequent deploys completely idempotent.

Live production examples: teletext.onurcanari.com (originally finance-checks; Next.js on nixpacks) and minirumble.lol (Vite + Colyseus on docker-compose).


9. Real Board Snapshot

Here is the actual board distribution for galactic-boredom (a retro PSX-style web game I’ve been building) after about a week of solo development:

Board Status

In parallel, teletext ran on its own board without either project waiting on the other.


10. Security & Hygiene Rules

  1. Secrets never touch docs, chats, task prompts, or git. Tokens live in profile .env files and OpenCode auth.json; scripts parse them at runtime.
  2. Canonical checkouts are sacred: The main branch only advances via squash-merge or fast-forward pull. Workers and reviewers work in their own isolated sandboxes.
  3. Hard gates are non-negotiable: If the review infrastructure fails or tests break, there is no silent merge β€” it escalates directly to me.
  4. Never bypass interactive safety prompts: If a state-changing command pauses for approval in a chat session, handle it explicitly.
  5. The task body is a contract: Workers must strictly adhere to the defined scope.

11. Step-by-Step Checklist for Replicating This Setup

  1. Install Hermes Agent and bind the Telegram gateway to a dedicated profile (e.g. coder).

  2. Set up OpenCode CLI, authenticate providers, and optionally add oh-my-opencode-slim with your agent presets.

  3. Prepare the workspace directory layout: workspace/, workspace/repos/, and .worktrees/.

  4. Configure the four core scripts: project-register, project-task, project-list, project-deploy.

  5. Install the skill bundle: multi-project (orchestrator), agent-git-workflow + opencode + github-pr-workflow (worker), mr-review-merge (pipeline), kanban-worker (auto-injected).

    πŸ“¦ Ready-to-Use Skill Bundle: Download the sanitized archive containing all custom skills, reference manuals, and helper scripts (ghapi.py, telegram_notify.py, webprobe.py):

    πŸ“₯ Download hermes-skills.zip

  6. Wire your MCP servers: Cloudflare (remote MCP) and Dokploy (stdio MCP).

  7. Install Dokploy on your VPS, configure Traefik (80/443), and connect your GitHub App.

  8. Register your first project with project-register and dispatch your first task from Telegram.

Hard-Learned Gotchas

  • Never set default_workdir on kanban boards (all parallel tasks will collide on a single checkout).
  • The hermes binary might not be in default shell PATHs β€” use absolute paths in automation scripts.
  • Fresh worktree clones lack git identity β€” ensure git config user.name/email is set before commits.
  • Avoid parse_mode=Markdown in Telegram bot alerts when branch names or task IDs contain underscores (_), which cause HTTP 400 errors.

12. Why This Architecture?

  • Telegram as the primary input: I can trigger features, review diffs, and resolve blockers on the go from my phone with a single sentence.
  • Kanban as an asynchronous buffer: Decoupling requests from execution makes work durable, observable, retryable, and parallel. If a session drops, no progress is lost.
  • Fresh-context review: Asking an AI agent to critique its own code introduces blind spots. Splitting author, reviewer, and fixer roles dramatically elevated output quality.
  • Automated verification gates: Replacing manual code review with deterministic checks (green test suites, zero critical findings, protected path guards) removed the primary bottleneck of solo development.

13. What’s Next? Future Plans & Optimizations

While the system is running smoothly in production, I’m continuously fine-tuning it:

  • RAM & Memory Management (8 GB β†’ 16 GB): Running multiple concurrent tasks with heavy parallel builds (next build, vite build, npm ci) occasionally hit cgroup memory ceilings and triggered OOM kills on 8 GB RAM. I upgraded the VPS to 16 GB, which resolved stability under heavy multi-task loads.
  • New Skill & Agent Architectures: Planning to integrate specialized skill sets and agents such as Ponytail, Caveman, and RTK to expand coding and research capabilities.
  • Token Efficiency: Optimizing prompt structures, context handoffs, and log trimming to further reduce model token consumption and latency.
  • Smart Caching in OpenCode: Adding prompt/response caching and build artifact caching to eliminate redundant work.

Note: This post was compiled from my personal notes and production setup on my VPS; editing, tone, and flow were refined with AI assistance.