Where an agent earns its place in a Thread
Two decisions come before choosing a platform. First, which rung each generation belongs on. Second, where a Thread's state lives once an agent writes its messages. About 12 minutes.
Updated 2026-09-16. You have since allowed agents to write memory and Postgres to shrink to a harness, and the ADK TypeScript package turned out to ship a Postgres-backed session service. The ladder and the placement exercise still hold. The "session-per-job" rule below applies only under the original assumptions. See Lesson 3 for the revised design.
Why this matters now
Your map commits to an agentic rewrite after the MVP. Ticket 13 · Generation engine seam is still open and asks exactly this: "Which generations are expected to go agentic, and which stay plain calls", and how a slower agent fits the job dispatch. By the end of this lesson you can answer the first half of that ticket.
The ladder
Anthropic's guidance draws one line. In a workflow, "LLMs and tools are orchestrated through predefined code paths". In an agent, the LLM "dynamically direct[s] its own processes and tool usage". They recommend starting with the simplest option.[1] Google made the same argument for ADK 2.0: model-driven routing is "slow, expensive, and exhibit[s] variance compared to a workflow or deterministic code".[2] For this project that gives four rungs:
- Plain LLM callYour code assembles every input, and one call returns a fixed shape. This is the MVP today.
- Workflow (ADK 2.0 graph)Code fixes the order of the steps. Some steps are deterministic functions (load, validate, record) and some are LLM calls. ADK 2.0 makes these typed
node()s joined by edges.[3] - Agent with toolsThe model decides what to fetch next, such as opening another Project file or checking earlier Lessons, and loops until it is done. In ADK this can be a single agent node inside the graph.
- Managed agent sessionA vendor runs the loop and hosts a sandbox and session state: Claude Managed Agents[4] or Gemini's Antigravity agent.[5]
The climbing test. Move a generation up a rung only if (a) the model has to decide what context to fetch part-way through, (b) the job can wait for the slower result, and (c) the gain is worth several times the tokens. Your own research estimates about $0.01 per Lesson for plain calls and $0.03–0.15 for an agent loop (engine research).
A Thread is not an agent session
It is tempting to map one Thread to one long-lived agent session, with every Reaction or Reply as a new message to it. Check that against what you already decided:
- A Thread is never closed:
/nextand the morning run start a newer one, and older Threads still accept Replies and Exercise/Repetition taps (ticket 12, decided 2026-09-17). Progress lives on the Topic, not the Thread (ticket 06). - Generators never write memory. They return fixed shapes, and the bot validates and records them in append-only Postgres (ticket 07).
- Reactions are handled by rules, not the LLM: a toast (and, on the Topic's latest Lesson, a progression step) within the webhook's 1–2 s acknowledgement (ticket 04).
| Session-per-Thread | Session-per-job (recommended) | |
|---|---|---|
| What the agent is | A stateful conversation partner | A stateless generator behind the seam |
| Thread memory | In the vendor's session history | In your Postgres, which the agent reads through tools or an input bundle |
| Sources of truth | Two, which can drift (the same problem ADR 0001 avoided) | One |
| Swapping engines | Needs the history migrated | Change the adapter only |
| Platform support | Gemini keeps environments for 7 days[6]. ADK TS 2.1 can store sessions in Postgres (DatabaseSessionService; the docs are behind the code)[7] | Works on all three |
ADK 2.0 can pause a graph for a human with RequestInput and resume it later.[8] That fits a pause of minutes inside one job. For a Reaction that comes the next morning, send it as a new event to a stored session instead (Lesson 3).
Practice: place each generation
Pick a rung for each item, then read why.
1. Reply classify: Instruction or Note, with a placeholder shown in about 2 s.
2. A Lesson: select the focus → gather Postgres rows and GitHub files → write → validate → return a fixed shape.
3. Answer feedback: given the Exercise, its hidden answer and the Answer, return feedback and an outcome.
4. Refreshing a Project digest: clone the repo, read many files, and list Candidate improvements. It is slow and latency doesn't matter.
5. A Follow-up for the Instruction "show me where my own w2tAgent code does this".
6. Where should the targeted Thread's "last ~6 messages" come from when an agent writes a Follow-up?
Before you leave: say the climbing test from memory, then open this
The model must decide what to fetch mid-task · the job can wait · the gain is worth several times the tokens. And whatever rung a generation is on, Thread state stays in Postgres: session-per-job.
Anything unclear, or disagree with a placement? Ask me, your teacher, in the Claude Code session. Pushback on these answers is useful input for ticket 13.