Claude · 17 · Part 8 · Hands-On Prompts

Reading Claude's Output

A good prompt is half the job; the other half is reading what comes back without being fooled by fluency. This chapter opens up a real, short session and shows every event in it: each tool Claude called, what came back, and what you were finally shown. Then it shows what the cost and permission fields mean, and how to ask Claude to explain what it did, and how to check that explanation against the log.

3
Turns in the session
2
Tools called
1
Self-report checked
Information current as of: 2026-10-31. The session was run with Claude Code 2.1.314, model claude-sonnet-5-5, read-only, against the bookshelf project at commit f23d2f5.
01
Mental Model

One Answer, Several Turns

Claude Code answers by looping: the model asks to use a tool, Claude Code runs it (if permitted) and hands the result back, and the model decides whether to call another tool or write the answer (Source 1). Each trip around that loop is a turn. A question that looks like one answer to you may be several turns underneath.

What happens after you press Enter
Your prompt Model Permission? Tool runs Answer if denied, the model is told result goes back: next turn no more tools needed: write the answer

Two consequences. First, more turns cost more, because the conversation so far is sent again each turn (the cached part is cheaper). Second, you can only trust the tool calls, not the prose: the log below shows what actually ran.

02
Real Session

A Complete Timeline

The prompt, sent with claude -p and --output-format stream-json --verbose, which emits one JSON event per step:

Prompt as sent
Which tests cover the title search feature? Read only. List each test and the file it lives in.
Actual events · executed 2026-10-31 · session init event removed (it lists the machine's installed skills and local paths)
#EventContent
1Grep call{"pattern": "search|title", "glob": "**/*[Tt]est*", "-i": true, "output_mode": "content"}
2Result returned to Claude1353 characters; starts: src/test/java/com/example/bookshelf/BookControllerTest.java:32: .andExpect(jsonPath("$[0].title").value("Clean Code")); src/test/java/com/example
3Claude thinks(reasoning is not recorded in the log)
4Read call{"file_path": "<project>/src/test/java/com/example/bookshelf/BookSearchTest.java"}
5Result returned to Claude1175 characters; starts: 1 package com.example.bookshelf; 2 3 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 4 import static org.springframework
6Answer shown to youOnly one test covers title search: - `titleSearchIsCaseInsensitiveAndSorted`, in `src/test/java/com/example/bookshelf/BookSearchTest.java:21`. - It calls `GET /api/books/search?title=CLEAN`. - It expects a 200 response with 2 results, "Clean Architecture" first and "Clean Code" second. - So it checks case-insensitive matching and sorted order. I searched the test files for "search" and "title", and `BookSearchTest` is the only file that exercises the search endpoint. `BookControllerTest` and `BookApiIntegrationTest` only mention `title` as a field on books they create or list. Nothing tests a search with no matches, a missing `title` parameter, or partial or substring matching beyond this one case.

Totals from the same log: 3 turns, 7.5 s, estimated $0.072. Tokens: 6 fresh input, 653 output, 66380 read from cache, 14583 written to cache.

Reading it. Claude searched all test files for "search" or "title" with one Grep call, then opened the one file whose matches touched the search endpoint, then answered. The model's reasoning between steps is not in the log. Notice what it did not do: it never opened the controller or ran any test. The answer is therefore about which tests exist, not whether they pass.
03
Fields Worth Knowing

Cost, Turns and Denied Tools

With --output-format json the final result carries fields that every sample in this guide records. The ones that matter most:

FieldWhat it tells youCaveat
num_turnsHow many trips around the loop. The session above: 3More turns usually means more reading, not necessarily a better answer
total_cost_usdClaude Code's estimate for the run. The session above: $0.072Client-side estimate at list prices, not an invoice (Source 2)
usageTokens: fresh input, output, and cache reads and writesCache reads are most of the input here; they are billed at a lower rate
permission_denialsTools Claude tried but was not allowed to runAn empty list does not prove nothing risky was attempted, only that nothing was blocked

A real denial is worth looking at. In Recipe 1 (Chapter 16) Claude tried to read many files with one shell command (cat over a dozen files). The run was read-only with Bash not allowed, so it was denied and recorded:

Actual output · permission_denials from the R-01 run (command shortened)
[{"tool_name": "Bash", "tool_input": {"command": "cat CLAUDE.md src/main/resources/application.properties; cd src/main/java/com/example/bookshelf && cat BookController.java ... ; ls mcp"}}]

The denial did not stop the run: the model was told no, and carried on with the Read tool. It is also a free audit trail. If you see a Bash denial you did not expect, find out why Claude wanted a shell.

04
Asking For An Explanation

"Explain What You Just Did"

Library prompt MET-03 asks Claude to describe its own steps. The same session was continued with --resume so the explanation refers to the real run above:

Prompt as sent (resumed session)
Explain what you just did in plain English, step by step, including any files you read or changed.
Actual output · executed 2026-10-31 · 1 turn, estimated $0.082
Here's what I did, step by step: 1. **Searched the test files.** I ran one content search (Grep) over files with "test" in their names. It looked for the words "search" or "title", ignoring case. That turned up matches in three files: - `BookControllerTest.java` - `BookApiIntegrationTest.java` - `BookSearchTest.java` 2. **Judged the matches.** In the first two files, "title" only appeared as a field on books the tests create or list. The only match that touched the search endpoint (`/api/books/search`) was in `BookSearchTest.java`. 3. **Read one file in full.** I opened `src/test/java/com/example/bookshelf/BookSearchTest.java` to check it held no other relevant tests. It has one test, `titleSearchIsCaseInsensitiveAndSorted`. 4. **Answered you.** I named that test and its file, described what it checks, and noted what isn't covered: no-match results, a missing parameter, and partial matching. **Files read:** `BookSearchTest.java` (in full). The search also scanned the other test files, but only for matching lines. **Files changed:** none. I did nothing except search and read, as you asked. I didn't open the main source code, such as the controller. I only looked at tests.
Author's check: matches the log. The log shows one Grep and one Read, as claimed. The claim that matches appeared in three files is also right: the Grep result lists lines from BookControllerTest.java, BookApiIntegrationTest.java and BookSearchTest.java. The cited BookSearchTest.java:21 is the test method, and the described assertions (200, two results, "Clean Architecture" then "Clean Code") match the file. It correctly says it changed no files and did not open the main source.

One run agreeing with its log is not proof that it always will. A self-report is the model's account of its actions, written afterwards. The log is the record. For anything that matters, compare the two, as above, or use a hook that records tool calls yourself (Chapter 10).

05
Habit

A Reading Checklist

CheckHow
Did it read what it cites?Open every file and line it names. Across the samples in Chapter 15, citations were mostly right and sometimes off by one line
What was verified versus assumed?Add VER-03. A sample there (DBG-04) guessed code it had not opened
Did anything change?git status and git diff. Read-only prompts should leave both empty
Was anything blocked?Look at permission_denials
Is a claim measured or marketing-shaped?"Noticeably faster" with no number is a guess (DOC-05 in Chapter 15)
Does the cost make sense?A one-line question that used eight turns probably searched too widely: narrow the scope
06
Summary

Key Takeaways, Exercises and Sources

∑ Reading Claude's output: what to remember
  • An answer is the end of a loop of turns. Tool calls are what happened; prose is a summary.
  • Look at what it did not read. The sample session never opened the controller; its answer was about tests existing, not passing.
  • Cost and turns are cheap signals of how widely Claude searched.
  • Denials are an audit trail. Read them.
  • A self-explanation is useful and checkable. Check it against the log for anything important.
Exercises

Exercise 1 Beginner

Run any read-only question with claude -p "…" --output-format json and find num_turns, total_cost_usd and permission_denials in the output. Which surprised you?

Learning outcome: read the evidence fields.

Exercise 2 Intermediate

Repeat with --output-format stream-json --verbose. List the tool calls in order. Before you look at the answer, predict what it will say, then compare.

Learning outcome: connect tool calls to conclusions.

Exercise 3 Advanced

Resume the session with MET-03 and write down every claim in the explanation. Mark each one confirmed or not confirmed by the log. If any claim is not in the log, find out why.

Learning outcome: audit a self-report.

Sources (read on 2026-10-30; paraphrased)
  1. Anthropic, How Claude Code works — the agentic loop, tools, turns.
  2. Anthropic, Manage costs — cost tracking and caching.
  3. Anthropic, Run Claude Code programmatically — output formats and --resume.

The timeline and the resumed explanation are real, executed on 2026-10-31 (tools/capture_stream.sh; event log in prompts/samples/STREAM-01.timeline.json). The raw log is not published because its init event lists local configuration. Turn counts and costs come from that run only. The loop diagram is a simplification.