To implement a runner correctly, you must adhere to three core principles:
1. Takopi owns the domain model
Runners must not invent new event types. They are responsible for translating engine-specific output into the core types defined in takopi.model:
ResumeToken(engine, value)StartedEvent(engine, resume, title?, meta?)ActionEvent(engine, action, phase, ok?, message?, level?)CompletedEvent(engine, ok, answer, resume?, error?, usage?)
2. The runner contract (invariants)
Every run must follow these lifecycle invariants:
- Exactly one
StartedEvent must be emitted. - Exactly one
CompletedEvent must be emitted. - The
CompletedEvent must be the last event in the sequence. CompletedEvent.resume must match the StartedEvent.resume (using the same token).
Note: A minimal runner only needs to emit StartedEvent → CompletedEvent. Adding ActionEvents is recommended for better progress UX.
3. Resume lines are runner-owned
The runner is the sole authority for managing how sessions are resumed in chat. You must implement logic for:
format_resume(): How the resume command looks in text.extract_resume(): How to parse a token out of text.is_resume_line(): How to reliably detect if a line is a resume command.