Harden Living UI workflow engine and fix build-loop feedback bugs#388
Open
ahmad-ajmal wants to merge 1 commit into
Open
Harden Living UI workflow engine and fix build-loop feedback bugs#388ahmad-ajmal wants to merge 1 commit into
ahmad-ajmal wants to merge 1 commit into
Conversation
- Generic Workflow engine: pure check-report parser, phase property,
JSONL run journal, engine-owned round counting (recorders can no
longer inflate the budget), generic spawn-outcome tap
- Split LivingUIManager into Ownership/Ports/Tunnels mixins
- Ownership funnel: ghost guard keeps registry-named owners (any
status), so parked tasks survive restarts and replies route to them
- Feed pipeline errors verbatim into the next work round; fixlog
captures failure blocks only, trims at attempt boundaries
- PocketBase: accept legacy options.{values} field format, name the
failing field in import-rejection errors
ahmad-ajmal
force-pushed
the
improvement/living-ui-V2-test
branch
from
July 17, 2026 11:02
4ffc9d0 to
62765c7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Workflows & the Agentic Loop
How a task turn flows through the shared loop, where deterministic
workflows plug in, and what changes when a task has no workflow at all.
The layering
app/subagent/runner.py(SubAgentRunner) is the secondAgentLoopsubclass — the blocking loop that runs a spawned sub-agent from start to
sub_task_endinside one action. Same skeleton, different executionpolicy (it executes actions itself;
TaskTurnreturns decisions foragent_baseto execute between limits/persistence/triggers).One task turn, hop by hop
A trigger fires →
agent_base._select_action_in_task→ActionRouter.select_action_in_taskconstructs aTaskTurnand callsrun_turn(task).TaskTurn.__init__resolves the task's workflow:resolve_task_workflow(task)maps the persistedTask.workflow_idback to the registered workflow object (or
None).AgentLoop.run_turnconsults the step program:TaskTurn.step_programreturnsworkflow.step— this single lineis the whole coupling between the loop and
Workflow.Workflow.step→compute: load durableWorkStatefrom disk,bundle it into a
StepContext, and walk the stage chain — first stagewith an opinion wins:
wait_for_user → answer_user → bootstrap → budget_gate → work_round → check → finishThe returned step's
kindroutes the turn back in the loop:actionson_code_step→step_to_decisions→ validated payloads →agent_baseexecutesllmappend_step_directive— delivered even on delta turns),allowed_actionsbounds the candidateswaitendtask_enddecision (still subject to thetask_end_gatehook)NoneOutcomes come back through taps, not stages. The stages never
observe results; hooks record them into
WorkState, and the nextturn's
step()reads the new state:spawn_subagentcompletesconstruction_events._record_specialist_spawnrecord_spawn/record_walk_outcome(verdict, fixlog)living_ui_validatefinishesmanager.launch_and_verifywrapperrecord_validate_outcome(staged)registrationsuser_message_routedhookrecord_user_leadThe same skeleton, two behaviors
Every task — workflow or not — runs the identical turn skeleton. There is
exactly ONE fork point: what
step_programreturns.Everything else that differs is a consequence of the task carrying a
workflow_id, decided once at task creation:create_task(..., workflow_id="living_ui_creation")create_task(..., workflow_id=None)workflow.system_promptseeded into the session cachesinject_memory/include_skillsflags)workflow.task_state()directive block"llm"talk stepsagent_baseexecutes the returned decisionsWorkStateon disk, written by tapswait_for_user/answer_userstages → ONE bounded LLM reply"end"step;task_end_gaterefuses unvalidated completestask_end; no gate listener claims itThe two traces below are concrete runs of the left and right columns.
Flow A — "Build me a habit tracker" (workflow-driven)
Budget exhausted instead?
stage_budget_gate→ one honest{"kind":"llm"}report withwait_for_user_reply=true(including thefix ledger's "already tried" block) → task parks; the reply is recorded
as a lead and the loop resumes.
Flow B — "Summarize my invoice emails" (no workflow)
Same trigger loop and executors as Flow A — only the right-hand column of
the table above applies.
Same trigger loop, same
run_turn, same executors — with noworkflow_idthe step program isNoneevery turn, the LLM makes everydecision from the event stream, and "memory" is the event stream itself
rather than
WorkState+ taps.Flow C — a second deterministic domain (hypothetical)
living_ui_creationis the only registered workflow today, but theengine is domain-generic: any produce-and-verify job plugs in by
subclassing and answering a handful of questions. Example — a
"researched report" workflow (worker = the already-registered
research_agent; checker = a hypotheticalfact_checksub-agent):Plus one outcome tap (the domain's equivalent of
_record_specialist_spawn) routingfact_checkresults intorecord_check_outcome. Then the identical machinery runs it:Nothing in
workflow.pychanges; the domain contributes onlysubject resolution, the two queries, and its outcome tap. All the loop
guarantees (round budget → budget-gate ask, durable state across
restarts, independent verification,
task_endgating) come for free.