This is the heart of the tutorial. You will write six prompts to Claude Code, and by the end, you will have a fully working daily report bot. No coding required — just clear communication.
Think of Claude Code as a brilliant colleague who can code anything, but needs you to explain the goal clearly. The better you describe what you want, the better the result.
The conversation loop is always the same:Let’s start building.
Before writing any code, give Claude Code the big picture. This helps it make better decisions at every step.Open your terminal, cd into your daily-report-bot folder, and type claude to start Claude Code. Then send this prompt:
Your prompt to Claude Code
Copy
I want to build a daily work report bot. Here's what it should do:1. Run every weekday morning via GitHub Actions2. Read my recent git commits from this repository3. Use OpenAI's API to turn those commits into a friendly, human-readable daily standup update4. Post the update to a Slack channel via a webhookThe bot should be written in Node.js. It should support a "dry run" modethat prints the report to the console without posting to Slack.I also want a "commit banking" feature: if I make 10 commits on Mondaybut none on Tuesday, the bot should spread them across the week so everyday has something to report.Can you start by creating a project structure with a package.json andthe main entry point? Don't write the full logic yet — just set up theskeleton.
What happens: Claude Code creates a package.json, a main script file (e.g. index.js or src/index.js), and possibly a config file. It sets up the basic project structure without filling in the logic.
Communication skill: Setting context. Notice how the prompt starts with the big picture (“daily work report bot”), then lists specific requirements, then asks for a specific first step. This gives Claude Code enough context to make smart choices about project structure, naming, and dependencies.
View the generated project structure
Claude Code will typically create something like:
Copy
daily-report-bot/ package.json src/ index.js # Main entry point commits.js # Will collect git commits summarise.js # Will call OpenAI slack.js # Will post to Slack bank.js # Will handle commit banking .env.example # Template for environment variables
The exact structure may vary — that’s fine. Claude Code is making reasonable decisions based on your description.
Now let’s build the first real piece — the script that reads your git commits.
Your prompt to Claude Code
Copy
Now build the commit collector. It should:1. Use git log to read commits from the last 24 hours (or a configurable time window)2. Extract the commit message, author, and timestamp for each commit3. Return them as a structured array4. Handle the case where there are no commits gracefully5. Use a separator that won't conflict with shell operators — not || or &&Export the function so other parts of the project can use it.
What happens: Claude Code writes a function that runs git log with the right format string, parses the output, and returns a clean array of commit objects.
Communication skill: Breaking work into steps. Instead of asking Claude Code to build everything at once, we’re doing one piece at a time. This makes each step easier to review, and if something goes wrong, you know exactly where.
Prompt 3: Add the Smart Distribution (Commit Banking)
This is the cleverest part of the bot. If you do all your work on Monday, you don’t want Tuesday through Friday to report “nothing done.” Commit banking spreads your commits across the week.
Your prompt to Claude Code
Copy
Now build the commit banking feature. Here's how it should work:- Keep a "bank" of unposted commits in a local JSON file called state.json- When new commits come in, add them to the bank- Each day, calculate how many commits to include in today's report: divide the total banked commits by the remaining weekdays this week (including today), and round up- Take that many commits from the bank for today's report- Save the remaining commits back to state.json- On Friday, use all remaining commits so the bank starts empty on Monday- If there are no commits in the bank at all, return an empty arrayMake sure state.json can be committed to git so GitHub Actions canpersist it between runs.
What happens: Claude Code creates the banking logic with functions to load, save, and distribute commits across weekdays.
Communication skill: Describing business logic in plain language. You didn’t write any algorithm — you described the behaviour you wanted. “Divide by remaining weekdays, round up, empty on Friday.” Claude Code translates this into working code.
How commit banking works in practice
Here’s what happens in a real week:
Day
New commits
Banked total
Today’s batch
Remaining
Monday
10
10
2 (10 / 5 days)
8
Tuesday
0
8
2 (8 / 4 days)
6
Wednesday
3
9
3 (9 / 3 days)
6
Thursday
0
6
3 (6 / 2 days)
3
Friday
2
5
5 (all remaining)
0
Every day has something to report, even if you didn’t commit that day.
Now we connect to OpenAI to turn raw commit messages into a friendly daily update.
Your prompt to Claude Code
Copy
Now build the summariser. It should:1. Take an array of commit objects (message, author, date)2. Send them to OpenAI's chat completions API (use gpt-4o-mini to keep costs low)3. Ask OpenAI to write a friendly daily standup update from these commits4. The system prompt should tell the AI to: - Write in first person - Group related work together - Keep it concise (3-5 bullet points) - Use a warm, professional tone - End with any blockers (or "No blockers" if none)5. Return the formatted textUse the OPENAI_API_KEY environment variable for authentication.
What happens: Claude Code creates a function that formats commits into a prompt, calls the OpenAI API, and returns the summary text.
What you asked
What Claude Code built
You described the behaviour — take commits in, get a friendly summary out. You specified the model, tone, format, and how authentication works.
Claude Code wrote the API call, crafted the system prompt, handled errors, and returned clean text. It made decisions about temperature, token limits, and error handling that you didn’t need to think about.
Communication skill: Specifying integrations and output format. When connecting to external services, tell Claude Code which API to use, what model, and what the output should look like. The more specific you are about the result, the less you’ll need to iterate.
View the generated code
Copy
// src/summarise.jsconst OpenAI = require('openai');const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });const SYSTEM_PROMPT = `You are a helpful assistant that writes daily standup updates.Given a list of git commits, write a concise daily update in first person.Group related work together. Use 3-5 bullet points.Keep the tone warm and professional.End with "Blockers: None" unless the commits suggest otherwise.Do not include commit hashes or timestamps.`;async function summariseCommits(commits) { if (commits.length === 0) { return "No updates today — no recent commits to report."; } const commitList = commits .map(c => `- ${c.message} (${c.date})`) .join('\n'); const response = await client.chat.completions.create({ model: 'gpt-4o-mini', messages: [ { role: 'system', content: SYSTEM_PROMPT }, { role: 'user', content: `Here are my recent commits:\n\n${commitList}\n\nWrite my daily standup update.` } ], temperature: 0.7, max_tokens: 500, }); return response.choices[0].message.content;}module.exports = { summariseCommits };
Now build the Slack posting module. It should:1. Take the summary text from the summariser2. Post it to Slack using an incoming webhook URL3. Use the SLACK_WEBHOOK_URL environment variable4. Format the message nicely for Slack (use mrkdwn format)5. Add a header like "Daily Update — [today's date]"6. Handle errors gracefully — log the error but don't crashUse the native https module or fetch — no need for a Slack SDK.
What happens: Claude Code creates a small function that sends a POST request to the Slack webhook with a formatted message.
Communication skill: Building incrementally. Notice we didn’t try to build Slack posting in Prompt 1. By this point, Claude Code understands the whole project. It knows the summariser returns text, and it connects the pieces naturally.
The last build step — connect all the pieces and add a dry-run mode for safe testing.
Your prompt to Claude Code
Copy
Now wire everything together in the main entry point. It should:1. Collect recent commits using the commit collector2. Pass them through the commit banking system3. Send the batch to the OpenAI summariser4. Post the summary to SlackAdd a --dry-run flag (or DRY_RUN=true environment variable) that:- Skips the Slack posting step- Prints the summary to the console instead- Still updates state.json so we can test the banking logicAlso add a --channel flag or SLACK_CHANNEL environment variable thatdefaults to "test". When set to "prod", use SLACK_WEBHOOK_PROD insteadof SLACK_WEBHOOK_TEST.Add helpful console.log messages at each step so I can follow what'shappening when it runs.
What happens: Claude Code creates the main script that orchestrates all the pieces, with command-line flags and environment variable support.
Keep your API keys safe. Never commit .env files, API keys, or webhook URLs to git. We’ll store them as GitHub secrets in the next section.
Communication skill: Requesting integration and testing. This prompt brings everything together and asks for testing support (dry-run mode). Always ask for a way to test safely before connecting to real services.
View the generated code
Copy
// src/index.jsconst { getRecentCommits } = require('./commits');const { getTodaysBatch } = require('./bank');const { summariseCommits } = require('./summarise');const { postToSlack } = require('./slack');async function main() { const isDryRun = process.argv.includes('--dry-run') || process.env.DRY_RUN === 'true'; const channel = process.argv.includes('--channel') ? process.argv[process.argv.indexOf('--channel') + 1] : process.env.SLACK_CHANNEL || 'test'; // Set the right webhook URL based on channel if (channel === 'prod') { process.env.SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_PROD; } else { process.env.SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_TEST; } console.log(`Running daily report (dry-run: ${isDryRun}, channel: ${channel})`); // Step 1: Collect commits console.log('Collecting recent commits...'); const commits = getRecentCommits(); console.log(`Found ${commits.length} new commit(s).`); // Step 2: Bank and batch console.log('Processing commit bank...'); const batch = getTodaysBatch(commits); console.log(`Today's batch: ${batch.length} commit(s).`); if (batch.length === 0) { console.log('No commits to report today. Exiting.'); return; } // Step 3: Summarise console.log('Generating summary with OpenAI...'); const summary = await summariseCommits(batch); console.log('\n--- Daily Report ---'); console.log(summary); console.log('-------------------\n'); // Step 4: Post to Slack if (isDryRun) { console.log('Dry run — skipping Slack post.'); } else { console.log('Posting to Slack...'); await postToSlack(summary); } console.log('Done!');}main().catch(error => { console.error('Error:', error.message); process.exit(1);});
Sometimes you need to look something up — Slack’s webhook format, GitHub Actions syntax, or an error message. That’s where Claude in Chrome comes in.
Research with Claude in Chrome
Apply with Claude Code
Open the Slack API docs or any documentation page in Chrome
Click the Claude in Chrome extension icon
Ask it to explain what you’re reading, e.g.: “What format does Slack expect for incoming webhook messages?”
Use the answer to refine your next prompt to Claude Code
Take what you learned from your research and feed it back to Claude Code:
Your prompt to Claude Code
Copy
I looked up the Slack webhook format. It supports blocks with"mrkdwn" type for rich formatting. Can you update the Slackmodule to use blocks instead of a plain text payload?
Claude Code updates the code based on your research.
Instead of “build a Slack bot”, say “build a function that sends a POST request to a Slack incoming webhook with a formatted message using blocks.” The more specific, the fewer iterations.
Give context about your situation
Start with the big picture. Tell Claude Code what the project is, who it’s for, and what tools you’re using. Context helps it make better decisions about architecture, naming, and dependencies.
Ask Claude Code to explain what it did
If you don’t understand the code, ask: “Can you explain what this function does in plain language?” Understanding the code helps you spot issues and write better follow-up prompts.
If something breaks, describe the error
Copy and paste the exact error message. Tell Claude Code what you expected to happen and what actually happened. Don’t try to diagnose the problem yourself — let the AI help.
Iterate — refine your request step by step
Your first prompt rarely produces the perfect result. That’s normal. Review what Claude Code built, identify what’s not quite right, and send a follow-up prompt. Each iteration gets you closer.