Skip to main content
This is the first complete agent in the course. It is small on purpose, but it is not a toy. You will build a real coding agent with:
  • a typed state
  • a real LLM harness (the wiring layer that connects a transport, parser, and protocol into a coherent model-facing configuration)
  • a real system prompt
  • a real parser (a component that converts raw model output into a typed Decision)
  • real tools
  • a real reduce() (a function that folds the current observation and decision into the next state) loop
  • real qita traces (structured logs of all run events and steps)
You will study examples/patterns/react.py, but the lesson is written so you do not need to reverse-engineer that file to understand why it works.

What you are building

The task is tiny:
  • open buggy_module.py
  • fix add(a, b) so it returns a + b
  • run a verification command
That small task is useful because it lets you see the whole QitOS kernel (the core AgentModule + Engine execution loop) without extra orchestration noise.

The design for this lesson

Why we start with the text ReAct harness

The first lesson uses:
with:
That gives you the most transparent possible path: messages -> text model output -> ReAct parser -> Decision -> tool execution We do not start with native tool calling, XML, JSON, or model-specific harnesses (the wiring layer that connects a transport, parser, and protocol) because those add coupling before you understand the core loop.

The system prompt is a contract, not decoration

The lesson uses the canonical ReAct prompt:
In code, that is:
This matters because ReActTextParser is not doing magic. It expects exactly this style of output. The first durable QitOS lesson is:
  • prompt format and parser choice are one design decision
  • if you change one, you usually need to change the other

The full model harness for this lesson

The example builds the model like this:
Why this harness is appropriate here:
  • it works with OpenAI-compatible endpoints
  • it keeps the response in plain text
  • it stays compatible with the prompt-injection tool schema path used by REACT_SYSTEM_PROMPT
  • it keeps the lesson portable across research labs and local gateways
You are not choosing the best model here. You are choosing the simplest harness that exposes the kernel clearly.
1

Design the state around the next step

The state is intentionally small:
Why these fields?
  • scratchpad stores the compressed trajectory (the sequence of observations and decisions across steps) that the next model step can use
  • target_file keeps the agent grounded in one file
  • test_command makes the success condition executable
This is your first QitOS habit:add only state that changes future decisions
2

Expose a minimal tool surface

The example uses a manual registry so you can see exactly what is being exposed:
This is important. CodingToolSet is a bundle, but you still control its surface.For lesson 1, the right tool surface is just enough to:
  • inspect files
  • edit files
  • run the verification command
Do not expose a richer toolset until the task requires it.
3

Bind the prompt to the parser

The agent constructor pairs the prompt contract and the parser:
Read that as one sentence:“This agent asks the model to speak ReAct text, and the Engine parses that text with the ReAct parser.”In QitOS, this pairing is the harness (the wiring layer that connects a transport, parser, and protocol).Later lessons will change prompts and protocols. For now, keep this pair fixed.
4

Prepare only the context the next step needs

prepare() curates the current step’s input:
This is the second core habit:prepare() is not a state dump — it is a prompt-ready view of state.
5

Use reduce to define what the agent remembers

ReAct learns inside reduce():
Three lessons are in this one function:
  • not every observation (the environment’s response after an action or reset) belongs in future context
  • state is where you keep the compressed working memory
  • final_result is a clean, explicit success signal
6

Notice what we are not using yet

We do not use:
  • decide() overrides
  • explicit planning
  • memory adapters
  • custom history implementations
  • context compaction
  • model-specific protocol overrides
That is not because QitOS lacks them. Lesson 1 is about seeing the default path clearly before you bend it.
7

Run the example and inspect the kernel with qita

Run it:
Then inspect it:
In qita, check:
  • the exact prompt text sent to the model
  • whether the parser produced clean Thought and Action fields
  • whether the tool output made the verification condition obvious
  • whether final_result is set at the first true success condition

Why there is no separate memory or compaction yet

For this lesson, the right memory choice is “none.” Why:
  • the run is short
  • the useful context is already visible in scratchpad
  • adding retrieval or compaction here would blur the architecture before you understand it
In QitOS, memory is not a badge of sophistication. It is an answer to a concrete long-run problem.

Full example

The full runnable lesson lives at:

What lesson 2 changes

Lesson 2 keeps the same model harness and the same execution parser, but introduces a new idea: planning should become explicit state and explicit control flow, not a longer hidden thought.

Next lesson: PlanAct

Add a planner, a cursor, and a decide() gate without changing the core runtime.

Related reference: kit

Review ReActTextParser, prompt templates, and coding tool surfaces used in this lesson.