[KongchangAI]
· 4 min read· 2,262 words

Build an AI Coworker with Claude Code That Works While You Sleep

Build an AI Coworker with Claude Code That Works While You Sleep

Building a scheduled cloud doc-monitoring Agent with Claude Code routine — the core is role separation and draft-only, never publish.

The article tells how a Claude API tutorial author, after missing the Haiku 5.5 release by five days, built the `claude-docs-watch` repo: using Claude Code's routines (cron-triggered cloud sessions that auto-clone a GitHub repo and use MCP connectors on claude.ai) to monitor 12 official doc pages daily. The core design trade-off has a Python script handle fetching and generating unified diffs, while the model only reads diffs to judge and write, avoiding digesting ~300,000 characters of full text each day. The prompt's key boundary is "draft only, never publish" — the empty What I verified section at the end of the draft is filled in by a human after running the real API. The author also documented the first run's failures: Slack channel not found and a push conflict requiring a pull first, then summed up three pitfalls all pointing to permissions and connections rather than the prompt, and finally gave a comparison of three implementation paths with selection advice.

A Real Pain Point: I Was 5 Days Behind

The story starts a bit awkwardly. An author writing a Claude API tutorial missed the Haiku 5.5 release by a full 5 days — and the problem wasn't a lack of monitoring. Quite the opposite: he had long ago written a local script that pushed a "docs have changed" notification to Slack every day. The result? Nobody was reading it.

Too many notifications, too fragmented, no judgment — that's the same as no notification at all.

So he changed his approach: instead of letting a script "report changes," he'd have an AI coworker "understand the changes," then write a Japanese-language summary of what really mattered and post it to Slack every morning. And when a change affected his book manuscript, it would even auto-draft an article and push it to GitHub. The whole thing needs no server, no extra toolchain — just one feature of Claude Code.

Claude Code daily monitoring in practice

What Exactly Are Claude Code's routines

Claude Code has a feature called routines: a cloud session launched on a cron schedule that automatically clones your GitHub repo, uses the MCP connectors you've attached on claude.ai (like Slack or Gmail), and exits when the job is done.

A few key characteristics worth remembering:

  • Triggered by a 5-field cron expression (UTC timezone) or a one-time timestamp, with a minimum interval of 1 hour
  • When the session starts, your GitHub repo is already cloned, but it cannot see your local files, local environment variables, or local services
  • It can use MCP connectors attached on claude.ai; MCP servers configured only in local Claude Code are unavailable
  • The model, allowed tools, and prompt are packed into a single JSON object; the prompt is read from scratch on every run, so it must be self-contained
  • Create, update, run-immediately, and run logs can all be handled via API (inside Claude Code, via the RemoteTrigger tool) — only deletion requires the web UI

In other words, routines give you a "scheduled cloud Agent with a repo and Slack built in," and the entire infrastructure layer is abstracted away.

MCP (Model Context Protocol) is an open protocol led by Anthropic for wrapping external services (Slack, Gmail, GitHub, databases, etc.) into "tools" that models can invoke in a standardized way, thereby plugging those services' capabilities into a Claude session. You can think of it as "the USB-C port of the AI world": once a service implements an MCP Server, any MCP-compatible client can call it uniformly.

In this example, Slack is an MCP connector — the routine uses it to send messages from the cloud. Pay special attention to the attachment location of MCP connections: only connectors attached to your claude.ai account and visible from the cloud will be used by the routine; an MCP Server configured only in your local Claude Code environment cannot be accessed by the cloud session. This explains the root cause of issues like "the Slack connector was attached to the wrong workspace" mentioned below — it's not a script bug, but a connector-scope problem. The same logic applies to GitHub: which repos the cloud can access depends on which repos you've authorized on claude.ai.

The Key Design Trade-off: Let Python Find the Diff, Let the Model Make the Call

The repo this author built is called claude-docs-watch, and its structure isn't complicated:

  • pages.json: the 12 official doc pages being monitored
  • watch.py: fetch → compare with state/ → generate diffs/<date>/ and result.json (standard library only)
  • state/: yesterday's text
  • diffs/: each day's unified diff
  • drafts/: drafts the model writes when a change is important
  • log/: daily summaries
  • ROUTINE_PROMPT.md: the instructions the routine receives

The most important design decision is: Python finds the diff, the model only makes judgments and writes.

The reasoning is very practical — if you let the model "read all 12 pages and then tell me what changed," it would need to digest roughly 300,000 characters every morning, which is both slow and prone to missing things. But if watch.py generates diff files first, the model only needs to read a handful of diffs. This is a classic separation of "grunt work" from "judgment work," and it's the dividing line for whether a scheduled Agent like this is usable at all.

unified diff is the text format produced by diff -u or git diff, using a leading - for deleted lines, a leading + for added lines, a preceding space for unchanged context lines, and hunk markers like @@ -old_start,count +new_start,count @@. Its value lies in its signal-to-noise ratio: 12 pages can easily run to hundreds of thousands of characters, but what actually changes is often only a few hundred characters. Expressed as a unified diff, the input the model reads can be compressed to a thousandth of the original or even less.

This is also the technical precondition that makes the "Python finds the diff, model makes the call" design work. If instead you had the model read the full text every round, not only would token consumption be high and speed slow, but it would also be extremely prone to missing key changes due to diluted attention. Fixing the detection stage as deterministic string comparison and reserving the judgment stage for the model is a universal cost-and-reliability optimization for this kind of scheduled Agent — essentially, using "cheap deterministic code" to do the grunt work the model isn't good at, leaving the model's compute for the reasoning and writing that truly require judgment.

How to Write the Prompt: This Coworker Only Drafts, Never Publishes

In the routine's JSON config, the model is Sonnet 5.5. The author's assessment: "For routine tasks that just read a diff and summarize, it's more than enough." The allowed tools include Bash, Read, Write, Edit, Glob, Grep, plus Slack's two MCP tools.

The really interesting part is the prompt. It splits the whole process into 7 steps, and a few details show real craft:

  • Step one is git pull --rebase origin main, because the checkout may be stale
  • When there are no changes, it just appends a single log line, pushes, sends a brief Slack message, and stops
  • When there are changes, it reads each diff, ignores purely formatting changes, writes a per-page summary, and judges "affected / not affected / to be confirmed"
  • Only if at least one page is affected and it falls into one of five categories — new model, new pricing, breaking change, deprecation/retirement, or a new Managed Agents feature — does it write one draft article
  • The draft quotes the original text from the diff, links to the official page, and ends with a "What I verified" placeholder section

That last point is the core of the whole thing: this AI coworker drafts, and never publishes. The empty "What I verified" section at the end of the draft is left for a human to fill in after running the real API. The prompt even explicitly says: "do not claim that anything was tested."

That sense of boundaries is more worth copying than any automation trick.

"Human-in-the-loop" in human-AI collaboration means letting an automated system carry a task only up to a certain explicit point, with key decisions or external publishing still gated by a human. Here it's implemented through two mechanisms: first, an empty "What I verified" section is reserved at the end of the draft, forcing a human to actually run the API and fill it in before publishing; second, the prompt explicitly forbids "claiming that anything was tested," cutting off at the source the possibility of the model hallucinating "test results."

The motivation behind this is credibility: when content like tutorials or technical documentation contains a model-fabricated price, parameter, or behavior description, the cost far outweighs the time saved by automation. Compared with "letting AI publish everything and spot-checking afterward," keeping publishing rights in human hands is a safer default posture. It also incidentally solves the question of responsibility — if something goes wrong, the last editor clearly knows they didn't verify it. This boundary design is more transferable than specific automation tricks: any Agent whose output goes to external readers or users should draw a line for "which step must be confirmed by a human."

The First Two Runs: What Went Wrong Was All Permissions and Connections

The author candidly documented the full process of the first two runs (October 16).

First run (23 seconds, 8 turns): Sandbox allocation, repo clone, watch.py finds no changes, log append, push succeeds — then Slack fails to send with channel_not_found. The Agent looked for the channel itself and couldn't find it, so it fell back to sending a phone push notification. The cause: the Slack connector on claude.ai was attached to a different workspace. The author reconnected and wrote the channel ID directly into the prompt.

Second run (51 seconds, 9 turns): Slack sends successfully, then the push is rejected — the checkout in the sandbox predates the first run's commit. The Agent runs git pull --rebase, finds that its own commit is a duplicate line, discards it, and exits cleanly. The behavior is quite reasonable, but the author still adds git pull --rebase as step one to avoid reliving the same thing every morning.

Run logs are available via API, with timestamps for every tool call, every error, and the final message. In other words, you can replay in full what this coworker did while you slept, once you wake up.

Three Pitfalls That Will Really Trip You Up

The author sums up three pitfalls he hit, all pointing to the same thing: what goes wrong is not the prompt, but permissions and connections.

  1. The GitHub App must be installed on the organization. Connecting GitHub on claude.ai alone isn't enough — private repos under an organization require first installing github.com/apps/claude on the organization and authorizing that repo, otherwise creating the routine returns repo_access_denied.
  2. A connector points to only one workspace. When multiple Slack workspaces coexist, it's easy to attach to the wrong one, so use the channel ID, not the channel name.
  3. The checkout isn't necessarily fresh. Any routine that pushes should pull first.

Cost and Limitations: This Isn't for "5-Minute Polling"

  • Runs consume your Claude subscription plan's quota; the author saw no separate API billing; a no-change run costs roughly a few thousand tokens
  • The minimum interval is 1 hour, so it's not the tool for "5-minute polling"-type needs
  • It cannot access your local machine; everything the task needs must be in the repo or reachable from the cloud
  • Deletion can only be done in the web UI

The Same Job, Three Ways to Build It

The author gives a very practical comparison table listing three implementation paths:

Claude Code routineManaged AgentsLocal cron + API
Where it runsAnthropic cloudAnthropic cloudYour machine
Config effortOne JSONAgent + Deploymentplist/crontab + script
BillingPlan quotatokens + session time ($0.08/hour)API tokens
Best forPeriodic tasks that fit in a repo + connectorsLong-running Agents that need a managed toolboxTasks that need local files or local credentials
NotificationsConnectors (Slack/Gmail), pushWebhookRoll your own

The author's actual choice is to use all three together: this docs-monitoring job is a routine; the production Agent platform uses Managed Agents; and the weekly Search Console report stays on launchd because it needs a local OAuth token.

Managed Agents is another tier of hosting Anthropic offers: you first define an Agent (role, tools, system prompt), then deploy it as a Deployment, with the platform handling scheduling and execution. The key difference from routines is that it targets long-running Agent tasks that need a managed toolbox, priced in tokens plus session time ($0.08/hour in the example), whereas routines consume subscription plan quota.

Local cron / launchd is the fully self-managed route: scheduled tasks run on your own machine, so they can access local files, local environment variables, and local OAuth credentials — at the cost that the machine must be on, you have to handle failures yourself, and you have to implement notifications yourself. The selection criteria for the three are actually quite clear: start with "where does the task need things to be" — if it needs local files or local credentials, it can only stay on your machine; if everything fits in a repo plus connectors, a routine is the lowest-config-effort option; only if the task needs to run for a long time and carry a toolset does Managed Agents come into play. The author uses all three together precisely because of this criterion — each plays to its strengths.

Three Things Worth Taking Away

  • A Claude Code routine gives you a "scheduled cloud Agent with a repo and Slack," with zero infrastructure
  • Split the roles: Python handles detection, the model handles judgment and writing, the human handles publishing
  • What actually goes wrong is permissions and connections, not the prompt

The most valuable thing about this whole approach isn't that it can auto-post to Slack — it's that it draws a clear line: AI can do the judgment and the draft, but publishing rights stay in human hands. That line may be more worth learning from than the automation itself.

#Claude Code#routines#MCP#AI coworker#document monitoring
Share:

Related articles