Client Work — Agent Operations

The Cbarrgs Agent: A Coding Agent That Lives in My Client's Website

Cbarrgs is an independent electronic and ambient artist. His website is maintained by a full Claude Code session that lives inside the site's own repository and answers his Telegram messages — the same architecture, and nearly the same keepalive script, that runs my own personal agent. This is how I ship an AI agent to a client: a written job description, a two-person allowlist, hard escalation lines, and the honest numbers from launch week.

Joseph Blas
15 min read
The Cbarrgs agent: a Telegram chat on a phone next to a terminal running the Claude Code session inside the website repo
Client production system — live since Aug 26, 2026

6

Days live

1,577

Watchdog heartbeats

5 min

Health-check cadence

2

People allowlisted

0

Client requests yet

A musician client messages a Telegram bot. The bot is a full Claude Code session running in tmux with his website's repo as its working directory. Under a written charter it can ship copy changes end-to-end — edit, build, push, verify live, report back — and it hard-escalates money, credentials, and redesigns to me. A systemd timer health-checks it every five minutes; a scheduled steward independently watches the site and the artist's public profiles. Six days in: the client is paired and talking, the watchdog has logged 1,577 heartbeats, and zero client-requested site changes have shipped yet.

Honesty first: this system is six days old. The artist paired on day two and we've exchanged messages, but he hasn't asked for a site change yet — every number on this page is launch-week telemetry, not a highlight reel. The one content change produced so far came from the monitoring side: an automated check caught a new single the site had missed for 12 days and staged the fix as a pull request that, as I write this, still waits on my merge.

Every developer who builds a website for a client meets the same question a month later: who keeps it alive? The client doesn't want a CMS login. You don't want a retainer made of copy-paste requests. My answer for Cbarrgs — a musician, a friend, and a client — was to give him what I run for myself: a coding agent that lives inside his website's repository and answers his Telegram messages.

This is not a chatbot bolted onto a website. It's a full Claude Code session running in tmux on my Linux box, working directory set to the site's repo, kept alive by a systemd timer that health-checks it every five minutes. When Cbarrgs messages the bot, the thing that answers can edit the code, run the build, push to main, watch Cloudflare Pages deploy, curl the live site to confirm the change landed, and reply that it's done — end to end. The keepalive script that resurrects it is a near-identical sibling of the one running my own agent. In fact, the client's copy shipped a day before mine did.

The Problem: Artist Websites Go Stale#

An artist's website has one job: be correct on the day someone checks it — usually a release day. In practice it decays quietly. This project's origin sin: the site's social-preview tags said the merch store was coming soon for four months after it went live. Then in August it happened again with higher stakes — Cbarrgs released the single Solitude on August 19, and cbarrgs.com kept headlining the previous EP. Nobody noticed for 12 days. The thing that finally noticed wasn't a human.

1

Release days are deadlines.

A drop needs the hero, the share cards, and the smart links correct that morning — not after the developer wakes up and finds time.

2

The client shouldn't need a dashboard.

Cbarrgs writes songs; he's not going to learn a CMS. The one interface he reliably opens every day is his messages.

3

Metadata rots invisibly.

OG tags, JSON-LD, sitemaps — nobody looks at them until a share card renders wrong or a search result lies. This site's "coming soon" tags sat stale for four months.

4

AI assistants read the site too.

When someone asks an assistant who Cbarrgs is, the answer builds on what the site serves to crawlers. A stale site quietly misinforms every one of them.

5

A retainer doesn't fit the workload.

Weeks of nothing, then a release day where everything changes at once. Billing monthly hours for that shape of work serves nobody.

The fix isn't a friendlier CMS. It's an agent that treats the website like a codebase — because it is one — and monitoring that treats staleness like an outage.

The Architecture: Telegram In, Deploy Out#

When Cbarrgs DMs the bot, the message lands in a Claude Code session whose working directory is the website's repo. That one decision does most of the work: the agent isn't calling some website API — it's a developer sitting inside the codebase, with the project's docs and its own written charter as context. Here's the full path from a message to a live site.

1

A Telegram DM arrives.

A pairing allowlist checks the sender before the agent sees anything. Exactly two chats are allowed: the artist's and mine. A guitar reaction acknowledges receipt.

2

The agent wakes up inside the repo.

The message reaches a full Claude Code session running in tmux, working directory set to the site repo, running unattended with permissions pre-granted.

3

It consults its job description.

A written charter plus the repo's own agent docs define what it may do alone, what escalates to me, and the brand rules it must never improvise around. It answers in whichever language the artist writes — Spanish or English.

4

Copy changes ship end-to-end.

Edit the code, run the build, rebase past dependabot's latest bumps, push to main on the public repo.

5

Cloudflare Pages deploys.

Push to main is the deploy. There's no pipeline to babysit.

6

Verify, then report.

The agent curls the live site to confirm the change actually rendered before telling the artist it's done.

Architecture diagram: a Telegram message passes a two-person pairing allowlist into a Claude Code session in tmux with the site repo as working directory, ships a change to Cloudflare Pages, verifies the live site, and replies
From a DM to a deployed site — with a 5-minute watchdog and a weekly steward watching from the side

Watched Every Five Minutes

A long-running agent session is a process, and processes die. A systemd user timer re-runs an idempotent keepalive script every five minutes: it checks that the tmux session exists and that the right binary is running with the right state directory and flags, and it restarts only when a check fails. Worst case, the agent is dead for about five minutes while the host is up. The log says this isn't theoretical: 1,577 healthy heartbeats and 8 session starts in the first six days, including four crashes resurrected inside the window — two of them on the evening I wrote this page. One honest caveat: this runs on my own Linux machine, not a datacenter, and the log shows host-off gaps in the first two days. It has been continuous since the afternoon of August 28.

Nobody — including me — noticed most of those restarts until I read the log for this article. That's the point of the watchdog: a crash becomes a log line, not an outage.

The Same Script That Runs My Own Agent

This is the part I'd put in the contract if clients read diffs. Run diff between the keepalive script for the client's agent and the one for my own personal agent and you get about sixty changed lines: session name, working directory, state directory, one extra health check on his side, one back-off guard on mine. Both descend from the same earlier script. And the file timestamps settle who got the good version first: the client's shipped a day before my own agent adopted it.

The client's agent isn't a stripped-down product tier of my setup. It is my setup, pointed at his repo.

Zero-Deploy Headlines

There's one more path, built for release days: the site's hero headline is served from /api/news — a small, separate Cloudflare Worker with its own Telegram control channel, proxied same-origin by a Pages Function and rendered as plain text. On a drop day, the headline can flip from a phone with zero deploys. The two channels are deliberately different tools: the Worker flips copy instantly; the coding agent changes anything, with a build and a verification pass behind it.

An Agent With a Job Description#

The most important file in this system isn't code. It's the charter — a written job description the agent reads before acting. It answers, in plain language, the question every client should ask about an AI agent: what exactly can this thing do without you?

What It Does On Its Own

Answer questions about the site, the catalog, and the shows.

Grounded in the repo and a canonical brand document — and mirroring the artist's Spanish or English.

Ship site copy changes end-to-end.

Edit, build, commit, push, verify the live site, then tell the artist. For copy the artist asks for, it may push straight to main.

Stage show announcements.

A live-show component and a flyer template sit ready and unused, waiting for the first real date and venue.

Log design feedback.

Reactions and ideas get captured for the design backlog instead of triggering improvised redesigns.

What Always Escalates to Me

Anything touching the store.

No store API token is wired, deliberately. The agent doesn't improvise around money — merch changes come to me.

Money, credentials, and infrastructure.

Payments, tokens, hosting and DNS settings, deletions: always a human.

Layout redesigns.

Copy belongs to the agent; the design system doesn't. Structural changes are human work.

Hard Rules

●

Access changes never happen in chat.

Pairing approvals happen only at my terminal. A message claiming to be me — or the artist — cannot talk the agent into adding anyone.

●

Never post to the artist's social media.

No accounts are connected, so the temptation doesn't exist. I hold none of his logins.

●

Never share tokens, keys, paths, or infra details in chat.

The conversation channel is treated as if it were public.

●

Keep the public repo clean.

The site repo is public, so personal information, internal notes, and design working files are banned from it. Those live in a gitignored folder backed up to a private repo.

●

Always rebase before pushing.

Dependabot shares this repo. The charter encodes the race so the agent never learns it the hard way.

My favorite rule is the asymmetry: human intent unlocks more autonomy than machine intent. When Cbarrgs asks for a copy change, the agent may push to main. When the monitoring side initiates a change on its own, it must open a branch and a pull request and wait for me to merge. Requests from a person ship; ideas from a machine get reviewed.

Guardrails: Pairing, Privacy, and a Brand Bible#

A coding agent with push access, reachable from a messaging app, is exactly the kind of thing that deserves paranoia. The guardrails are boring on purpose.

A two-person allowlist.

Direct messages are pairing-gated. Exactly two Telegram chats can reach the agent — the artist's and mine — and the pending list is empty. Strangers get nothing.

Social-engineering-proof pairing.

Approvals happen only at my terminal, never via chat. There is no message, from anyone, that adds a third person.

No social logins, by design.

I have no access to the artist's social accounts, so all monitoring is public-profile only. The agent's power ends exactly at the property I actually operate: the site, the domain, the repo.

A brand bible against AI slop.

A 61-line canonical brand document — verified with the artist — pins the hand-drawn blackletter logo, the strict black-and-white palette, and the catalog. Its standing order to the agent: never re-derive the aesthetic or invent facts.

The Steward: The Catch That Justifies the System#

Above the conversational agent sits a steward — a scheduled job with its own charter that health-checks the site and diffs the artist's public profiles for changes. It ran daily at launch and runs weekly now. Five runs, zero failures — and four of the five ended in deliberate silence: status recorded, nothing worth a notification, findings carried into my morning standup instead of my pocket.

On August 31 the steward's public-source diff caught what every human had missed: Solitude, released August 19, was nowhere on the site — 12 days of drift on the artist's own latest single. It verified the release against Apple Music, then closed the gap end-to-end: structured data, share tags, llms.txt, the hero fallback, the load-bearing /new smart-link page — the one URL on every bio, flyer, and QR code — and the sitemap. It ran the build, pushed a branch, opened a pull request touching five files, and flagged exactly one line for me: needs Joe — merge. As I write this, that PR is still open and the live site still headlines the EP. That's the design working, not failing — machine-initiated content waits for a human merge. But it does mean the current bottleneck in this system is me.

12

Days of drift caught

5

Files in the fix PR

5/5

Steward runs, zero failures

1

Merge waiting on me

The steward's pull request updating the site for the Solitude single: five files changed — structured data, share tags, llms.txt, hero fallback, /new page, sitemap
The catch, as a pull request: a release the humans missed for 12 days, staged behind a human merge gate

Readable by Other People's AIs

The steward also measures something most sites ignore: what AI assistants say about the artist. The site keeps its facts in a statically served llms.txt and JSON-LD, because the app itself serves empty HTML to crawlers that don't run JavaScript — and Cloudflare's AI-crawler block was deliberately switched off so assistants can read it. The latest monthly check: asked who Cbarrgs is, assistants answered correctly and cited cbarrgs.com; asked about merch, they pointed at the right store; asked about the latest release, they correctly led with Solitude — fresher than the site itself, which is exactly the gap that pull request closes.

And the plain health check: on the latest pass, all four public surfaces — the homepage, /new, /api/news, and llms.txt — returned HTTP 200. One honest footnote: my separate 30-minute uptime cron watches other projects and doesn't include cbarrgs.com yet; this site is health-checked on every steward run instead. Adding it is a one-line edit I simply haven't made.

Six Days In: The Honest Scorecard#

A case study written in launch week owes you the unflattering numbers alongside the flattering ones. Here is all of it, as of September 1.

MeasureNumberThe honest read
Watchdog heartbeats1,577Every five minutes since Aug 26, plus 8 session starts. Four crashes auto-recovered — two on the night I wrote this.
Continuous uptimeSince Aug 28 pmNot literally 24/7: it runs on my own Linux box, and the log shows host-off gaps in the first two days.
Bot conversations2 sessions, 6 repliesOnboarding-scale. Launch night was me testing; the artist paired on day two and has been replied to since.
Client-requested changes0Six days in, he hasn't asked for one yet. End-to-end capability is proven by the steward's PR, not by him.
Commits since launch63 dependabot bumps, 2 CI merges, 1 steward content commit. Zero artist-driven.
Site surfaces up4 of 4Homepage, /new, /api/news, llms.txt — all HTTP 200 on the latest check.
Money moved by the agent$0By design. No store API token exists, and everything financial escalates to a human.

Launch Week, Day by Day

Aug 25

Groundwork day

Brand document verified with the artist; llms.txt and JSON-LD shipped; the four-month-stale share tags finally fixed; the steward cron created — and its very first run flags stale campaign copy.

Aug 26

The bot goes live

Keepalive script, tmux session, five-minute watchdog. I test it from my own chat that night — three replies, all to me.

Aug 27

Reality intrudes

Host-off gaps appear in the log over the next two days, because the host is my own machine. Each time it comes back, the watchdog resurrects the session within minutes.

Aug 28

The artist pairs

Cbarrgs pairs in the late afternoon and gets his first reply from the agent that evening.

Aug 29

Quiet confirmation

The steward run records: paired, live, replying — and stays silent, because nothing needed me. A midday crash is auto-restarted inside the five-minute window.

Aug 31

The catch

The steward's public-source diff finds Solitude 12 days after release, builds the fix, and opens the pull request.

Sep 1

Where it stands

1,577 heartbeats logged. All four site surfaces return 200. The PR still waits on my merge, and the artist hasn't asked for anything yet.

Whether this becomes the story of a musician running his website by text message depends on the next six months, not the first six days. What launch week proves is narrower and, to me, more useful: the pattern transfers. The same session-in-tmux, watchdog-on-a-timer, charter-in-a-file architecture that runs my own agent now runs a client's — with a real trust boundary drawn around it.

Stack

Claude Code

The agent itself: a full coding session with the repo as its world

T

Telegram

The client interface — a paired bot DM via the Claude Code channels plugin

tmux

Holds the long-running session on the host

s

systemd

User timer firing the idempotent keepalive script every 5 minutes

C

Cloudflare Pages

Push to main is the deploy for cbarrgs.com

G

GitHub

Public site repo; dependabot, CI, and PRs as the human merge gate

Lessons#

1

Write the job description before the code

The charter — what the agent may do alone, what escalates, what it must never do — did more for this system's safety and usefulness than any prompt engineering. It's also the artifact that turns "an AI has push access" from alarming into explainable. I'd show it to any client before showing them the bot.

2

Sell what you dogfood, literally

The client's keepalive script and my own differ by about sixty lines of naming and guards. His shipped first. There's no demo-versus-production gap to apologize for, and every fix I make for my own agent is a fix his inherits.

3

Trust boundaries beat capability limits

The agent could technically touch the store, the DNS, the layout. It doesn't, because a written charter says money, credentials, and redesigns escalate to a human. Capability is what it can do; the charter is what it will do — and clients buy the second thing.

4

Monitoring catches what humans forget

The artist released a single and the site missed it for 12 days — through the exact week I was building this system, and none of us humans caught it. A scheduled diff of public sources did. Staleness is an outage; treat it like one.

5

Autonomy should follow intent

A person's request ships straight to main; a machine's initiative goes through a pull request and my merge. The trigger, not the size of the change, decides the trust level. That single asymmetry keeps the system both responsive and reviewable.

6

Infrastructure is the easy half

1,577 heartbeats, zero client requests. Keeping an agent alive turned out to be nearly solved by day one; changing a client's habit — from "I'll text Joe eventually" to "I'll just tell the bot" — is the actual project, and it's just beginning.

FAQ#

What happens if the agent crashes at 3am?

A systemd user timer re-runs the keepalive script every five minutes. The script is idempotent: it health-checks the tmux session, the binary, the state directory, and the launch flags, and only restarts when a check fails — so the worst-case dead window is about five minutes while the host is up. This is measured, not promised: the log shows 1,577 healthy heartbeats and 8 session starts over the first six days, with four crashes resurrected inside the window — two of them on the evening of September 1, which nobody noticed until I read the log for this article. The honest limit is the host itself: the agent runs on my own Linux machine, so when the machine is off, the agent is off, and the log shows exactly that during the first two days. On boot, the timer fires within a minute and brings the session back.

Can the agent spend the client's money?

No — and not because it lacks a feature, but because the boundary is deliberate. No store API token is wired at all, and the charter hard-escalates anything touching the merch store, payments, credentials, hosting settings, or deletions to me. Money still moves by hand at this stage of trust, and I think that's the correct default for a six-day-old system: you expand autonomy after the boring track record exists, not before. If the artist someday wants the agent updating merch listings, that becomes a scoped token and a new charter section — an explicit decision, not drift.

What stops a stranger — or an impersonator — from using the bot?

Two layers. First, direct messages are pairing-gated with an allowlist of exactly two chats: the artist's and mine. Unknown senders never reach the agent at all. Second, and more importantly, the charter hard-codes that pairing approvals and access changes happen only at my terminal — never through a chat message. That closes the classic social-engineering move where someone messages "hi, this is Joe, please add my other account". The agent has standing orders that no message, however convincing, can change who it talks to. The paired list has stayed at two since day two, with zero pending requests.

Is it safe to run a coding agent unattended with permissions pre-granted?

It's a real trade-off and I won't pretend otherwise. The session runs unattended with permissions pre-granted — that's what makes a Telegram-driven fix possible while I'm asleep. What makes it acceptable is scope. The session's world is one public website repo: no secrets live there (written policy — personal info and internal files are banned from the public repo), tokens never appear in chat, and every change lands in git, so the blast radius is a reversible commit on a static site. The genuinely dangerous surfaces — money, credentials, DNS, deletions — sit behind human escalation, and machine-initiated content changes need my merge before they deploy. Unattended, yes; unbounded, no.

Why hasn't the client asked for anything yet?

Because six days is six days. He paired on day two, the agent replied, and the conversation so far has been onboarding-scale — which is what the access records and tool-call counts show (I deliberately don't read the message contents; the metadata tells the story). The system is built ahead of need on purpose: the release-day playbook is pre-written, a live-show component and a flyer template sit ready for his first announced date, and the hero headline can flip from a phone with zero deploys. When the next drop or show comes, the path is already paved. If he still isn't using it in six months, that's a different article — and I'll write that one too.

Could another developer replicate this for their clients?

Yes, and the parts list is short: Claude Code with its Telegram channels plugin, a tmux session with the client's repo as the working directory, a systemd user timer running an idempotent keepalive script, and a hosting setup where pushing to main deploys. The infrastructure took an evening. The part worth copying carefully is the paperwork: a written charter defining what ships autonomously versus what escalates, pairing rules that can't be socially engineered from inside the chat, a brand document so the agent never improvises the client's aesthetic, and repo hygiene rules if the repo is public. Every incident this design prevents traces back to one of those documents, not to the code.

The Cbarrgs agent is one client's slice of a larger operation. These case studies cover the agent infrastructure it grew out of and the production AI-ops discipline behind it.

Ask

Open the chat and ask how the charter is written, how pairing stays social-engineering-proof, or what I'd change before onboarding a second client. Or read how I run the same architecture for myself.

Joseph Blas

Joseph Blas

AI Developer · Autonomous Systems Builder · Multi-Agent AI Systems Builder

Founder of Joe's Tech Solutions. Previously 10 years in autonomous vehicle systems at Google, Uber, and Otto — now building the AI systems that run small businesses.

More about the author →
© 2026 Joseph Blas. All rights reserved.|Privacy