BlitzBase is the AI knowledge base Dylan Haugen runs for Local Service Spotlight and BlitzMetrics client work: one folder of markdown where every client’s reconciled record lives, readable by humans in Obsidian and by Claude agents directly off disk. The one thing it couldn’t see was Basecamp, where the client communication actually happens. In a single evening session, a Claude agent connected them: it registered the OAuth app, wrote a dependency-free sync tool, mapped every active client project, pulled every Access and Updates thread into the repo as markdown, captured end-of-day check-in reports with their replies, and put the whole thing on a daily schedule. The test that proved it: asking “what did Dennis tell me to do in reply to my EOD yesterday?” went from a six-step browser hunt to a two-second local file read.
The agent that built the connection wrote this article from its own session log, the same way the other builds in this series were documented. The bugs and decisions below are the real ones.
Where This Fits in the Methodology
This is an agent-infrastructure build in the same series as the Cam Hazzard build and the internal link building workflow: each one documents a task an agent executed end to end so the next person, or the next agent, can replicate it. The format follows the meta-article prompt template. There is no parent definitive article on agent knowledge bases yet; this build is the argument for writing one.
The Integration Task
The goal, in Dylan’s words at kickoff:
“If the agents have context, then they can just do things a lot faster, and we want to have the raw Basecamp logs in there.”
Dylan Haugen, session kickoff
In scope: a Basecamp OAuth app, a sync tool that pulls each client project’s message-board threads (Access, Updates and its continuations, Meetings, Strategy Assessment, Project Overview) plus recent Campfire lines into each client’s folder, capture of automatic check-in answers (the end-of-day reports) with every reply, a live search mode for “find anything Dennis said about X this week,” a daily refresh schedule, and documentation so the whole thing is repeatable for a public distribution later. Out of scope: posting anything back to Basecamp. The connection reads; humans write.
Source Material Ingestion
Before touching Basecamp, the agent read the knowledge base’s own rules: the folder layout (a knowledge-base file at each client root, compiled/ for the reconciled wiki, raw/ for source material), the source-of-truth hierarchy that makes local files outrank live apps, and the existing operating rules for agents working in the repo. That dictated the design target: Basecamp content is raw input, so it lands in raw/basecamp/ per client, never in compiled/. The agent also read each client’s knowledge-base file to confirm which Basecamp project maps to which client folder, instead of guessing from project names.
Initial Build: OAuth App and a Dependency-Free Sync Tool
Basecamp has no simple API keys; everything goes through an OAuth app registered on the account. The agent drove the registration itself through the operator’s logged-in browser session, stopping only at the login screen (agents don’t enter passwords). Redirect URI: http://localhost:7652/callback, because the one-time authorization runs on the operator’s machine, catches the code on a local port, and exchanges it for tokens that auto-refresh from then on.
The sync tool itself is one Python file with zero dependencies outside the standard library, a deliberate constraint so it runs on a stock Mac with no installs. Four subcommands: auth (one-time browser authorization), projects (list and cache every project on the account), sync (pull mapped projects into the repo), and search (query recent activity across all projects by text, person, and day range). Credentials, tokens, and the project-to-client mapping live in a gitignored config folder, so nothing sensitive can ever reach the repo’s history.
Each synced thread becomes one markdown file: thread URL, timestamps, then every message and comment in order with author and date, converted from Basecamp’s rich-text HTML to readable markdown by a small parser that handles links, bold, lists, and image attachments. Each project also gets an INDEX.md listing every thread with its last-updated date, which is what an agent reads first to orient.
The EOD Loop: Check-In Answers With Replies
The highest-value content wasn’t in any message board. End-of-day reports live in Basecamp’s Automatic Check-ins, a different content type with its own API shape: a recurring question, answers per person per day, and comment replies on each answer. The replies are the payoff, because that’s where the feedback and assignments land. The sync’s check-in module pulls one person’s answers, filtered by creator so teammates’ answers stay out, bundles each answer with all of its replies, and writes monthly files into the personal folder.
The proof came the same night. Dennis replied to the previous day’s EOD, the sync captured it, and the comment that triggered the next piece of work was sitting in a local file:
“VERY NICE! Got a meta article showing what you (and your agents) have built?”
Dennis Yu, replying to Dylan’s EOD in Basecamp, as captured by the sync
The QA Marathon: Real Bugs and the Fixes
The EODs that weren’t where threads live
Symptom: the first live test (“check what Dennis said in reply to my EOD”) found nothing in any synced thread file. Cause: EODs aren’t message-board threads at all; they’re Automatic Check-in answers, a content type the message-board sync never touches, parked in a team project that wasn’t mapped. The agent had to find them the slow way once, through six browser navigation hops. Fix: a dedicated check-in module in the sync tool, driven by config (project, question, person, destination), so the slow hunt never happens again. The general lesson: a “sync everything” claim is only as true as the content types you’ve enumerated.
The archived threads that looked like a sync bug
Symptom: one client’s folder had two more thread files than its INDEX listed. Cause: not a bug in the new sync. The extra files were hand-pasted archives saved weeks earlier, and Basecamp’s API only returns active threads, so the sync neither overwrote nor indexed them. Fix: verified by file timestamps, then documented: archived Basecamp threads aren’t returned by the API, and legacy hand-saved files coexist untouched. What looked like corruption was the old workflow and the new one shaking hands.
The attachment captions that printed twice
Symptom: image attachments in synced threads rendered as a caption marker followed by stray whitespace and the same caption again. Cause: Basecamp wraps attachments in a custom bc-attachment element whose inner figcaption duplicates the caption attribute the converter had already emitted. Fix: a skip flag in the HTML parser that swallows everything inside the attachment element after emitting one clean marker, verified with a unit test on a captured fragment before re-syncing.
The sandbox that can’t reach Basecamp
Symptom: every direct API call from the agent’s sandboxed environment failed instantly. Cause: agent sandboxes allowlist their network destinations, and Basecamp’s API isn’t on the list. Fix: a division of labor that became the architecture. The agent writes and edits the tool through the shared filesystem; the tool executes on the operator’s Mac, where the network and the OAuth callback both live. Each execution is one paste into Terminal, and the agent reads the results off disk the moment they land. The same constraint produced the documentation rule that tells future agents to read the synced files instead of attempting live API calls from a sandbox.
The 7am schedule that never fired
Symptom: the morning after setup, the log file didn’t exist and every synced file still carried the previous night’s timestamps. The scheduled 7am job had done nothing, silently. Cause: two independent macOS behaviors, either one fatal. cron skips any job whose time passes while the machine is asleep, with no catch-up on wake; and macOS privacy protection blocks cron-launched processes from reading the Documents folder, so even on an awake machine the job would have died before writing its own log. Silent on both paths. Fix: replace cron with a user LaunchAgent. launchd treats a missed calendar interval as due and fires it when the Mac wakes, runs in the user’s session where the Documents permission can be granted once, and logs stdout and stderr to a file so the next failure has nowhere to hide.
<key>StartCalendarInterval</key> <dict> <key>Hour</key><integer>7</integer> <key>Minute</key><integer>0</integer> </dict> <key>StandardOutPath</key> <string>/path/to/your/kb/.basecamp/sync.log</string> # install (one paste, replaces any cron line): crontab -l | grep -v basecamp-sync | crontab - cp com.yourname.basecamp-sync.plist ~/Library/LaunchAgents/ launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.yourname.basecamp-sync.plist
If macOS asks whether the tool can access files in Documents on the first run, allow it once. That prompt is the same protection that was killing cron without ever asking.
Critical Decisions With Rationale
Standard library only, no installs. The sync tool refuses every dependency: OAuth, HTTP, pagination, rate-limit handling, and HTML conversion are all stdlib Python. The repo is meant to be distributable later as a public starter kit, and every dependency is a support ticket waiting to happen on someone else’s machine. One file, one paste, it runs.
Raw means raw. Synced files land in each client’s raw/ layer and are rewritten wholesale on every run. No merging, no summarizing, no agent commentary in the files. The knowledge base’s compiled layer is where reconciliation happens, and keeping the sync dumb means it can never corrupt the part humans curate.
Filter check-ins by person, keep every reply. A team check-in contains everyone’s answers, but the operator’s archive only needs their own, with all replies attached. Filtering by creator at sync time keeps teammates’ reports out of a personal folder while preserving the one thing that matters most: what the boss said back.
A local schedule, but launchd, not cron. The refresh runs at 7am from the operator’s own machine: no cloud scheduler, no background service, no third subscription. The first implementation was a single crontab line, and it failed its very first morning; the full story is in the QA Marathon below. The shipped version is a macOS LaunchAgent, which runs the missed job the moment the Mac wakes and writes a log the operator can check. A missed run still costs nothing, because every run rewrites everything anyway.
Read-only by design. The integration never posts to Basecamp. Drafts that agents produce (weekly client reports, EOD drafts) stay drafts until a human pastes them. That boundary is what makes a fully synced communication archive safe to hand to agents.
Effort and Cost Comparison
| Task | Agent Time | Human Time | Agent Cost | Human Cost ($50/hr blended) |
|---|---|---|---|---|
| OAuth app registration + auth flow | 20 min | 3 hrs | $0.60 | $150 |
| Sync tool (threads, comments, Campfire) | 1 hr | 8 hrs | $1.50 | $400 |
| Check-in (EOD) module with replies | 30 min | 4 hrs | $0.80 | $200 |
| Project mapping + folder scaffolds | 15 min | 2 hrs | $0.40 | $100 |
| Testing across four client projects | 30 min | 4 hrs | $0.70 | $200 |
| Docs: README, agent rules, schedule | 25 min | 3 hrs | $0.50 | $150 |
| TOTAL | 3 hrs | 24 hrs | $4.50 | $1,200 |
Pricing basis: the session consumed about 1.1 million tokens (1M input, 100K output), priced at Claude Sonnet public rates of $3 per million input and $15 per million output for comparability with the other builds in this series. Human cost uses a blended $50/hr. The ratio is roughly 265x. The human estimate covers a developer producing the same tool with tests and docs; the agent figure excludes the operator’s own minutes, which were a login, three Terminal pastes, and answers to a handful of decision questions.
What the Agent Handled vs What Needed a Human
Agent handled autonomously: the OAuth app registration through the browser, the entire sync tool, the HTML-to-markdown converter and its attachment fix, the project-to-client mapping verified against the knowledge base instead of guessed, the client folder scaffolds, the check-in module, the live search mode, the README, the agent-facing operating rules so every future session knows the Basecamp layer exists, and verification passes on every synced file.
Required human input: the Basecamp login (agents don’t touch passwords), three Terminal pastes (authorize, first sync, schedule), confirmation of which person was the fourth client, and the corrections that kept the work honest. The pattern from every build in this series held: agents execute, humans decide.
Information Ingestion Inventory
- 1 OAuth app registered; 1 authorization flow caught on a local port
- 120+ projects enumerated on the account; 4 active client projects mapped and synced
- 24 thread files and 4 project indexes written on the first sync, every message and comment preserved verbatim
- 3 months of end-of-day answers backfilled (26 answers) with every reply attached
- 1 LaunchAgent keeping all of it fresh daily, installed after the cron attempt failed silently (see the QA Marathon)
- 495 lines of dependency-free Python; ~1.1 million tokens consumed
- 5 named bugs caught and documented; 5 named decisions locked with rationale
Guidelines Compliance Scorecard
| BlitzMetrics Guideline | Status | Notes |
|---|---|---|
| Hook names person/result/timeframe | PASS | System, builder, result, one evening |
| Answer in first paragraph | PASS | |
| Short paragraphs (3-5 lines) | PASS | |
| Active voice | PASS | |
| No AI fluff phrases | PASS | Checked against the banned list |
| Title under 65 characters | PASS | 57 |
| H2/H3 structure | PASS | H3s only in the QA Marathon |
| Internal links to BlitzMetrics | PASS | 5 internal links, each URL once |
| Cross-link to sibling meta-articles | PASS | Cam Hazzard, internal link building |
| Parent definitive article linked | FAIL | None exists on agent knowledge bases; recommend writing one |
| Entity links follow decision tree | PASS | |
| Source video embedded | N/A | No video source |
| Featured image | NEEDS HUMAN | Suggest the Terminal sync output or an Obsidian graph screenshot |
| Real screenshots, no stock images | NEEDS HUMAN | Same as above |
| RankMath configured | PASS | Set in the draft payload |
| Author byline | PASS | Dylan Haugen |
| Categories and tags set | PASS | |
| Anchor text 3-6 words | PASS | |
| Evergreen framing | PASS | No dates in body |
| Specific CTA | PASS | Closing section |
Why This Creates Specific Value for the Team
Every agent session that touches a client now starts already briefed: the full Access and Updates history is sitting next to the compiled wiki it feeds, current as of 7am. Questions that used to mean logging into Basecamp and scrolling (“what did the client say about access,” “what did Dennis assign me yesterday”) are now local file reads, which makes them available to every agent, every session, at zero marginal effort. The check-in capture quietly builds something else too: a permanent, searchable archive of daily work and the feedback on it, which is the raw material for weekly reports, reviews, and exactly the kind of article you’re reading.
Why This Creates Value for BlitzMetrics
The $4.50-versus-$1,200 ratio matters less than what the pattern proves: the moat for agent work isn’t the model, it’s the context layer. A team that pipes its communication exhaust into a local, agent-readable knowledge base gets compounding returns from every future session, and the integration that does it costs less than lunch. This build is also the template for the planned public version of the knowledge base starter kit, where “connect your Basecamp” becomes a documented setup step anyone can run with their own OAuth app.
The Build Pattern
The pattern this build instantiates: give agents the same source of truth the humans use, keep it local, keep the pipe read-only, and let a schedule do the remembering. The agent registered the access, built the pipe, tested it on real client history, and documented the rules for the next agent, all in one session, with the human supplying logins and judgment. Compare it against the Cam Hazzard build linked above to see the same execute-and-decide split applied to a website instead of an integration. If you want your client communication flowing into an agent-readable knowledge base like this, reach out through the Marketing Mechanic framework page and ask about agent infrastructure.
Want this for your own system? The Basecamp connection now ships inside BlitzBase, our distributable AI knowledge base — the Basecamp integration guide covers what your agent walks you through: app registration, project mapping, and a daily sync that survives sleep.

