Goal (operator): the agent should be as useful to talk to as a good collaborator: answer questions about its plans and work, explain its choices, and ask when unsure, not only accept commands.
Today (control.py, planner.py, executor.py), there's no free-form conversation:
Idle and waiting states: in IDLE only use / status do anything, and in PR_OPEN only its commands. Other text gets a hint.
At a sign-off gate, any text other than approve is rejection feedback. A question such as "why SQLite?" throws the plan away and triggers a re-plan.
While a model works: replies are "busy; say 'stop'". The text is recorded in the transcript but not acted on.
Only the planner can ask the operator anything (ask_human), and only while planning.
The executor can't ask at all, though spec B1 says execution "may enter AWAIT_INPUT (ask_human) any time it's unsure". Its tools are read_file, write_file, list_dir, run_command, finish and consulting a stronger model. When unsure it can only escalate, which gives a fixed "milestone stopped" prompt.
Progress is one line of tool calls per executor turn, not an account of what it's doing and why.
Proposal (spec edit first: B1/B2 and A4's approval UI):
Questions never change state. A marked question (e.g. starting with ? or ask:; exact syntax to settle) gets an answer from a model reading the transcript, the current plan and the workspace, in any waiting state. It's never read as an approval, rejection or answer to a pending question.
Gate safety: approvals keep their exact grammar and revision binding (#74).
The model property to add: a question never changes the gate or the state.
Explain as well as act:
a plan comes with a short rationale and the main alternatives considered;
a revised plan says what changed in response to the feedback;
a finished milestone summarises what was done, what was verified and anything left open, instead of only "done".
The executor can ask (ask_human, per B1). It pauses in AWAIT_INPUT with the question, and the answer resumes the milestone. It must fit the existing stop, restart and no-stranding rules (#66) and the Quint model.
Progress in prose, at a sensible rate: what it's working on and what it found, rather than raw tool-call lines. Keep the raw lines available, e.g. via status or a verbose setting.
Open questions
Questions while a model is working: answer them concurrently, in a separate call that doesn't block the worker, or queue them until the work pauses?
Which role answers questions, and what's the cost cap? The planner's model knows the plan best; the consultant is cheaper.
Could unmarked text at a gate be classified (question vs feedback) instead of needing a marker? That's riskier for gate safety, so if tried it should default to asking, not rejecting.
Should Gitea issue and PR comments get the same question handling?
Scope:nisse-dev first. The same conversational layer is wanted for nisse-ops, so it belongs in the shared transport/orchestrator code.
**Goal (operator):** the agent should be as useful to talk to as a good collaborator: answer questions about its plans and work, explain its choices, and ask when unsure, not only accept commands.
**Today** (`control.py`, `planner.py`, `executor.py`), there's no free-form conversation:
- **Idle and waiting states:** in `IDLE` only `use` / `status` do anything, and in `PR_OPEN` only its commands. Other text gets a hint.
- **At a sign-off gate, any text other than `approve` is rejection feedback.** A question such as "why SQLite?" throws the plan away and triggers a re-plan.
- **While a model works:** replies are "busy; say 'stop'". The text is recorded in the transcript but not acted on.
- **Only the planner can ask** the operator anything (`ask_human`), and only while planning.
- **The executor can't ask at all,** though spec B1 says execution "may enter AWAIT_INPUT (`ask_human`) any time it's unsure". Its tools are `read_file`, `write_file`, `list_dir`, `run_command`, `finish` and consulting a stronger model. When unsure it can only escalate, which gives a fixed "milestone stopped" prompt.
- **Progress** is one line of tool calls per executor turn, not an account of what it's doing and why.
**Proposal** (spec edit first: B1/B2 and A4's approval UI):
1. **Questions never change state.** A marked question (e.g. starting with `?` or `ask:`; exact syntax to settle) gets an answer from a model reading the transcript, the current plan and the workspace, in any waiting state. It's never read as an approval, rejection or answer to a pending question.
- Gate safety: approvals keep their exact grammar and revision binding (#74).
- The model property to add: a question never changes the gate or the state.
2. **Explain as well as act:**
- a plan comes with a short rationale and the main alternatives considered;
- a revised plan says what changed in response to the feedback;
- a finished milestone summarises what was done, what was verified and anything left open, instead of only "done".
3. **The executor can ask** (`ask_human`, per B1). It pauses in `AWAIT_INPUT` with the question, and the answer resumes the milestone. It must fit the existing stop, restart and no-stranding rules (#66) and the Quint model.
4. **Progress in prose,** at a sensible rate: what it's working on and what it found, rather than raw tool-call lines. Keep the raw lines available, e.g. via `status` or a verbose setting.
**Open questions**
- **Questions while a model is working:** answer them concurrently, in a separate call that doesn't block the worker, or queue them until the work pauses?
- **Which role answers questions,** and what's the cost cap? The planner's model knows the plan best; the consultant is cheaper.
- **Could unmarked text at a gate be classified** (question vs feedback) instead of needing a marker? That's riskier for gate safety, so if tried it should default to *asking*, not rejecting.
- **Should Gitea issue and PR comments get the same question handling?**
**Scope:** `nisse-dev` first. The same conversational layer is wanted for `nisse-ops`, so it belongs in the shared transport/orchestrator code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
A concrete case from the second live run: a task sent in IDLE, before use <project>, gets "no active project; say 'use '". That reads as "discarded", so the operator sent the task again. In fact the message was recorded, and the planner built the plan from it after use. The reply should say what happens to the message, e.g. "noted; I'll plan this once you say use <project>" (listing known projects when there's more than one). Small enough to fix on its own ahead of the rest of this issue.
A concrete case from the second live run: a task sent in `IDLE`, before `use <project>`, gets "no active project; say 'use <project>'". That reads as "discarded", so the operator sent the task again. In fact the message was recorded, and the planner built the plan from it after `use`. The reply should say what happens to the message, e.g. "noted; I'll plan this once you say `use <project>`" (listing known projects when there's more than one). Small enough to fix on its own ahead of the rest of this issue.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Goal (operator): the agent should be as useful to talk to as a good collaborator: answer questions about its plans and work, explain its choices, and ask when unsure, not only accept commands.
Today (
control.py,planner.py,executor.py), there's no free-form conversation:IDLEonlyuse/statusdo anything, and inPR_OPENonly its commands. Other text gets a hint.approveis rejection feedback. A question such as "why SQLite?" throws the plan away and triggers a re-plan.ask_human), and only while planning.ask_human) any time it's unsure". Its tools areread_file,write_file,list_dir,run_command,finishand consulting a stronger model. When unsure it can only escalate, which gives a fixed "milestone stopped" prompt.Proposal (spec edit first: B1/B2 and A4's approval UI):
?orask:; exact syntax to settle) gets an answer from a model reading the transcript, the current plan and the workspace, in any waiting state. It's never read as an approval, rejection or answer to a pending question.ask_human, per B1). It pauses inAWAIT_INPUTwith the question, and the answer resumes the milestone. It must fit the existing stop, restart and no-stranding rules (#66) and the Quint model.statusor a verbose setting.Open questions
Scope:
nisse-devfirst. The same conversational layer is wanted fornisse-ops, so it belongs in the shared transport/orchestrator code.🤖 Generated with Claude Code
https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
A concrete case from the second live run: a task sent in
IDLE, beforeuse <project>, gets "no active project; say 'use '". That reads as "discarded", so the operator sent the task again. In fact the message was recorded, and the planner built the plan from it afteruse. The reply should say what happens to the message, e.g. "noted; I'll plan this once you sayuse <project>" (listing known projects when there's more than one). Small enough to fix on its own ahead of the rest of this issue.