Skip to content
Boris Novichkov
ResumeGitHub ↗
ENRU
All work

YouGile Agent Bridge

Mention an agent in a task chat and it starts working in your repository

A webhook receiver that turns a project-tracker conversation into a coding session. Mentioning the agent in a YouGile task spawns Claude Code in a configured working directory, and each task chat maps one-to-one onto a persistent session, so the agent remembers the thread when it is mentioned again.

Active
Role
Author
Period
May 2026 — present
request path
YouGile ──POST──▶ https://your.domain/yougile/webhook                      ▼  FRP / cloudflared / ngrok / nginx — your choice                  127.0.0.1:9100   (this service)                      ▼  first matching rule in rules.toml                  claude --dangerously-skip-permissions                  cwd = rule.workdir                  --session-id <chatId>   (first time on this chat)                  --resume     <chatId>   (subsequent)

The full path from a chat mention to a running agent, as documented in the project README.

The idea

The gap between “we should fix that” in a task tracker and a coding session is mostly copying: the task text, the repository, the context of what was already discussed. This closes it. Mention the agent in a YouGile task chat and it starts Claude Code in the working directory that task’s rule points at.

The part that makes it usable rather than a demo is the session mapping. Each task chat gets a Claude session id derived from the chat id, so the first mention starts a session and every later mention resumes it. The conversation in the tracker and the conversation with the agent are the same conversation.

Routing is configuration, not code

Which repository a task drives is decided by the first matching rule in rules.toml, alongside the prompt template for that trigger. Adding a new project to the setup is a config change; there is no dispatch logic to edit.

Most of the work was failure handling

The receiver runs on a small host behind whatever tunnel is convenient, which means the network is genuinely unreliable — and a webhook you do not notice has died is worse than not having one.

The behaviour above is the result. The one worth singling out is forcing IPv4: a broken or half-open IPv6 route was producing SSL handshake timed out on a host that was otherwise perfectly healthy, while curl connected instantly. urllib has no Happy Eyeballs, so it sat on the dead AAAA address until timeout. Dropping AAAA results — with a fallback for hosts that only publish them — made the whole class of failure disappear.

Second is /healthz. It deliberately never calls the YouGile API, because a health check that depends on the thing it is meant to report on stops answering exactly when you need the answer. It returns the resolved rule set, the last-known subscription snapshot from the background watcher, and how long ago the event loop last ticked.

what keeps it alive on a bad network
Forced IPv4
A half-open IPv6 route stalls urllib until timeout — it has no Happy Eyeballs. Dropping AAAA records removes the class of failure.
Capped exponential backoff
Every API call and attachment download retries on network errors, timeouts and 429/5xx.
Permanent vs transient
A 4xx is never retried — retrying a rejection just hides it.
Self-healing subscription
A watcher revives a subscription disabled upstream and retries a failed cycle in 60s rather than waiting for the next sweep.
Event-loop watchdog
If the asyncio loop wedges, the process is restarted rather than left silently alive.
Non-blocking /healthz
Returns the resolved rule set and loop heartbeat age without calling YouGile, so it stays truthful when the network is down.

Every one of these exists because of a specific failure seen in practice.