From Request to Resumable Flow

For PentAGI, the important question is not only what an agent decides to do, but where that decision lives after it is made. This chapter follows a single user objective as it becomes a persistent Flow, then a Task, then a sequence of Subtasks with their own message chains and states. Understanding that ownership lets a reader locate a failure, a pause, or a report: in setup, planning, one Subtask, the execution container, or the durable record that connects them.

Before testing begins, PentAGI builds the execution envelope

A Flow starts as more than a prompt sent to a model. The controller first creates a durable Flow record with an initial status and provider reference. The provider then performs a bootstrap sequence: it asks an LLM to choose a Docker image for the request, detects the response language, generates a short title, and resolves the tool-call identifier format expected by that provider. Those values are written back to the Flow before normal work begins.

This ordering has a useful consequence and a dangerous one. The useful consequence is that the later agent chain has a concrete environment: an image, a working directory, a language, a model configuration, and a tool-call format. The dangerous one is that setup itself depends on the provider. A custom or self-hosted backend that returns malformed function-call JSON can fail at the image-selection step, before a security tool has run. The selected image is not a cryptographic security decision either. Docker has a fallback path when an image cannot be pulled or created, but the source does not turn the LLM's choice into an allow-list or an image-attestation system. Setup is therefore an operational boundary that deserves the same scrutiny as the later scan.

Once the provider is prepared, the controller connects several workers to the Flow: message, agent, search, terminal, vector-store, tool-call, and screenshot logging. It gives the Flow executor the chosen image, an embedder when available, and the providers that will persist each kind of event. The executor prepares the primary container, synchronizes flow files, verifies that the container remains alive after startup, and publishes a Flow-created event. Only then does the initial user input enter the worker's input channel.

Container preparation is deliberately part of the lifecycle rather than an invisible side effect. PentAGI creates a per-Flow work area, assigns predictable ports in bridge mode, attaches the Flow's files under the container workspace, and keeps the container alive as a tool environment rather than launching one disposable process per model message. Startup is checked after Docker accepts the start request, because a process can die immediately while the daemon still reports that the start call succeeded. If preparation fails, the Flow should not proceed as though a terminal exists. This separates an infrastructure failure from a later testing failure and gives the operator a more useful point of diagnosis.

The executor also becomes the bridge between the persistent Flow and the runtime. It carries the Flow and user identifiers into log records, gives terminal operations access to the primary container, and attaches search, screenshot, vector-store, and tool-call providers. The result is not a single “agent container” in the abstract; it is a Flow-scoped environment whose commands, files, and outputs can be associated with a particular engagement. That association is what later allows a reviewer to ask which command produced a result rather than merely which model mentioned it.

That input creates a Task. The Task receives its own title, stores the original request, writes an input message to the log, and asks the provider to generate Subtasks. The Task is not the same thing as the user's message: it is the durable objective that will own a plan, results, and a final report. The Subtasks are not just headings in that plan. Each one becomes a worker with a description, a primary-agent message chain, and a state that the controller can update independently.

The separation matters when the target produces partial progress. A Task might still be active even though one Subtask has finished. A Subtask might be waiting for an answer while the rest of the Flow remains structurally intact. A terminal command can fail without making the entire Flow indistinguishable from a planning failure. The hierarchy gives the operator a vocabulary for asking what happened instead of receiving one undifferentiated “agent failed” message.

Status is the control surface

PentAGI's status model is simple enough to describe and consequential enough to shape the whole run. Flows, Tasks, and Subtasks can be created, running, waiting, finished, or failed. The states are not decorative labels in the UI: they determine which inputs are accepted, which workers may proceed, and whether an operator can resume or stop an activity.

A normal path moves from created to running. The Task worker selects a planned Subtask, and the Subtask worker marks it running before asking the provider to execute its primary-agent chain. If the chain reaches its completion barrier, the Subtask becomes finished. If the agent reports an unrecoverable problem, it becomes failed. If the chain invokes the user-question barrier, the Subtask becomes waiting. That state propagates to the Task and then to the Flow, so the outer system presents a waiting engagement rather than continuing as though the missing answer did not matter.

The reverse direction is just as important. When the user supplies input to a waiting Flow, the controller routes it to the waiting Task and Subtask, adds it to the saved message chain, and resumes execution. The Assistant can provide another route into the same control surface, but it cannot submit arbitrary input at any time: the flow-management handlers check whether the Flow is actually waiting, and planned Subtasks cannot be patched while a Task is running. These checks turn “human in the loop” into a state transition with preconditions.

A stop request also acts on ownership rather than merely killing a process. The Flow worker keeps a cancellable context for the current Task, waits for the Task worker to acknowledge the stop, and uses a timeout so a stuck operation cannot hold the control path forever. A canceled Task or Subtask is returned to a waiting state when it has not already completed, allowing a user to decide whether to provide input, retry, or finish the Flow. This is different from declaring every interruption a clean success. The state records that execution stopped before the normal completion path.

stateDiagram-v2 [*] --> Created Created --> Running: input / start work Running --> Waiting: ask checkpoint Waiting --> Running: user input Running --> Finished: task or flow completes Running --> Failed: unrecoverable error Waiting --> Finished: finish or close Waiting --> Failed: error while waiting Finished --> [*] Failed --> [*]

The same state pattern appears at different levels, but the meaning is not identical. A waiting Subtask means a particular agent chain needs an answer. A waiting Task means the Task cannot proceed until one of its Subtasks is resumed or the plan is otherwise resolved. A waiting Flow is the user-visible condition that makes new input meaningful. Status propagation is what connects these interpretations.

Status also determines what the system may safely mutate. While a Task is running, the Assistant cannot patch its planned Subtasks; otherwise the worker could be executing a plan that the database has already replaced. When a plan is changed while the Flow is waiting, the controller can invalidate stale in-memory Subtask workers before creating the replacement rows. These rules are easy to overlook because they are not model behavior. They are application-level ownership rules that stop a conversational request from racing the execution state.

Persistence gives the state machine a memory beyond the process that currently runs it. PostgreSQL stores the Flow, Task, Subtask, container, message-chain, and tool-call records. The in-memory workers make active execution responsive, but the database remains the durable reference for status and results. GraphQL subscriptions and Flow publishers then carry updates outward to the interface. This is why a Flow can be loaded again after a service restart instead of being reconstructed solely from a model's last response.

The logs are not all interchangeable. A message log records interaction and model-facing content. An agent log records delegation between roles. A terminal log associates input and output with a container. Search, vector-store, tool-call, and screenshot records preserve different kinds of operational context. Keeping these categories separate gives a reviewer more than a chronological transcript: it makes it possible to compare what the agent said, what the tool received, what the container returned, and what the controller believed the state to be.

There is an important qualification to that recovery. When a running Flow is loaded, incomplete Tasks can be continued. But a Subtask that was recorded as running is reset to created and replayed from the beginning of that Subtask. PentAGI preserves the engagement's hierarchy and stored chain; it does not claim exact instruction-level continuation of every external effect. Replaying may be the safest way to restore a coherent agent conversation, but it also means that the operator must consider whether a previous command changed the target before the interruption.

That replay boundary is especially important in security work. A scan may be harmless to repeat, while a state-changing command, credential attempt, or file operation may not be. PentAGI's persistence tells the system where it was; it does not automatically infer the real-world consequences of an action that occurred immediately before a crash. The operator's review of terminal logs and target state remains part of safe resumption.

Completion follows another ownership boundary. After planned Subtasks finish, the Task asks a Reporter agent to synthesize their results. The Task stores that result and publishes a report message. The report is therefore a second-order product: it summarizes Subtask results and the records around them. It is not identical to terminal output, search output, or the agent's private reasoning. A useful review asks whether the report's material claims can be traced back to those lower-level records, especially when a result was summarized or a provider failure forced a recovery path.

Why this structure changes the meaning of “autonomous”

A model operating in a plain chat can appear autonomous because the conversation hides the boundary between intention and execution. PentAGI makes that boundary more visible. The Flow owns the engagement; the Task owns the objective; the Subtask owns one bounded piece of work; the provider owns the agent chain; the executor owns the translation from tool call to runtime action; and the database owns the durable record. None of those owners is completely independent, but their separation makes the system inspectable.

It also exposes hidden coupling. Provider setup affects container choice and tool-call compatibility. Container readiness affects whether every later terminal action can run. A Subtask status affects Task and Flow input. A deleted or stale Subtask worker can affect shutdown unless the controller invalidates it. A report depends on completed results, not merely on the existence of a plan. The lifecycle is therefore causal, not merely chronological: each transition changes what the next component is allowed to assume.

This is the first concrete sense in which PentAGI's autonomy is bounded. The system can act for a long time, but it acts through named state transitions, persistent ownership, and preconditions. The next problem is that a Task rarely arrives with the right sequence already known. PentAGI must decide what the Subtasks should be, then revise that decision when the first evidence changes the situation.

References