---
title: "Running this project daily inside Claude Code · Blog"
description: "What it actually looks like to run video-to-text day-to-day inside Claude Code: the prompts, the subprocesses, why CLAUDE.md is load-bearing, and where subagents pay off."
source: "https://adhenawer.net/blog/en/claude-code-daily-workflow.html"
lang: en
---

This project — a static site of podcast and video transcripts translated to Brazilian Portuguese — used to be driven from WhatsApp. A 3rd-party agent (OpenCode, then a custom Hermes fork) would receive a URL, reuse my Anthropic subscription token, run the pipeline, and push to GitHub. That stopped working when Anthropic blocked subscription-token reuse in 3rd-party agents. Fair enough: the token is for the first-party client.

So everything moved into Claude Code, the official terminal CLI. It turns out that was an upgrade, not a downgrade. What follows is what "running the repo" actually looks like now — the prompts, the subprocess calls, and the handful of places where I still have to steer.

## The setup

There is no setup, which is the point.

```
cd ~/code/video-to-text
claude
```

The CLI starts, reads `CLAUDE.md` from the repo root, and that's the session. No WhatsApp gateway, no queue, no daemon. The project memory file is ~300 lines: folder layout, the pipeline command, slug conventions, the card template for `docs/index.html`, the sitemap update rule, the TDD requirement. Claude Code treats it as ground truth for every turn.

## A typical run

A normal session to add one article is one sentence from me and about two minutes of tool calls.

> **Me:** add an article from `https://youtu.be/abc123`, title "Obsidian + Claude Code", subtitle "Eduardo Mendes".

What Claude Code does next, without me asking:

1. Runs `python3 src/fetch_transcript.py 'https://youtu.be/abc123' --text-only --timestamps > /tmp/transcript_abc123.txt` and checks the exit code.
 2. Reads `/tmp/transcript_abc123.txt` into context.
 3. Translates to PT-BR, organizing the text into thematic sections using the `================` / `SECTION NAME` format that `build_html.py` expects. Fillers, ads, and `[music]` markers are dropped.
 4. Writes the result to `/tmp/abc123_pt.txt`.
 5. Runs `build_html.py` with the right positional args to produce `docs/leituras/obsidian-claude-code.html`.
 6. Edits `docs/index.html` to insert a new `<a class="card">` and the matching `showProgress('reading_abc123_', 'p-abc123')` line in the footer script.
 7. Adds a `<url>` entry to `sitemap.xml` with today's `lastmod`.
 8. Appends an entry to `llms.txt`.
 9. `git add` the five touched files, commits with the convention `feat: adiciona artigo — <Título>`, pushes.

The parts that actually need me are the translation itself (taste, not mechanics) and catching when a YouTube video has no captions — at which point I redirect to the Twitter/X provider or ask it to pull audio via `yt-dlp` and run `mlx-whisper` locally.

## Why CLAUDE.md is load-bearing

Without the memory file, Claude Code would still succeed at step 1 and then start inventing. Slug formats would drift (`obsidian_claude_code` vs `obsidian-claude-code`). The card HTML would get a new class name. The sitemap would be forgotten. Commits would be in English instead of the `feat: adiciona artigo — Título` convention.

The file isn't documentation for humans. It's a prompt. Every rule in it exists because the agent got it wrong once and I wrote down the fix. Representative entries:

```
Slugs: kebab-case PT-BR sem acentos → como-construi-sistema-suporte-cliente-ia.html
Traduções .txt: ficam em /tmp, não commitadas
Commits: feat: adiciona artigo — Título / fix: ... / style: ...
```

The "load-bearing" test is simple: if I delete a line from `CLAUDE.md`, does the next run break? For most of the file, yes. That's the signal that it's doing real work and not just sitting there looking like documentation.

## Subagents for big refactors

The single-article flow fits in one context. The backfill did not.

At one point I wanted to add English versions of 19 existing articles. Doing that serially meant loading 19 transcripts, 19 translations, 19 HTML generations into one conversation. The main context would blow up around article 6 and quality would drop for the rest.

The fix was the Task tool — Claude Code's subagent primitive. One prompt:

> **Me:** For each Portuguese article in `docs/leituras/`, spawn a subagent to produce the English version at `docs/readings/<slug>.html`. Each subagent should read its one source file, translate, run `build_html.py`, and return the output path. Run up to 4 in parallel.

Each subagent gets a fresh context window, does one article, returns a short summary, and exits. The main conversation sees only the summaries — nineteen lines of "wrote `docs/readings/x.html`" instead of nineteen full translations. The same pattern applies when I ask it to audit every article for broken links or missing JSON-LD.

Plan mode gets used for anything that touches shared code: adding a new provider in `src/providers/`, changing the CSS theme tokens, restructuring the test layout. `/plan`, read the plan, push back on two or three points, then approve. It's slower than letting it start immediately and much faster than undoing a bad refactor.

## Lessons learned

**Reference, don't paste.** Early on I would paste a transcript into the chat. That eats the context window and produces worse translations than just saying "read `/tmp/transcript_abc123.txt`". The agent is better at pulling from disk than parsing a wall of quoted text.

**Name the file, not the behavior.** "Add the card" is ambiguous. "Edit `docs/index.html` to add a new card following the pattern of the last entry" is not. The `@docs/index.html` reference shorthand pins the target.

**Review in a new turn.** When I want a sanity check, I open a fresh message: "review the HTML you just generated for missing `og:` tags". The model critiques its own output far better when it isn't defending it in the same turn.

**It is not magic.** Claude Code mis-parses YouTube URLs with trailing query strings about once a week. It has invented non-existent flags for `yt-dlp`. It occasionally stages a file I didn't want committed, which is why I read every `git status` before approving the commit. The workflow is fast because the agent is fast, not because the agent is infallible.

What changed moving off the WhatsApp gateway is that the feedback loop shrank from minutes to seconds. I see every tool call. I can interrupt. I can ask "why did you pick that slug?" and get an answer. The pipeline didn't get simpler; the surface I see got honest.

Repo: [github.com/adhenawer/video-to-text](https://github.com/adhenawer/video-to-text).