Practical engineering with agents · · 15 min read
Long builds without guesswork: processes, pipelines and artifacts
Keep the original run identifiable, catch intermediate failures, recover after interruption and verify the actual artifact.

A long build makes an agent workflow ambiguous when the conversation, process and result are treated as one thing. The agent can be quiet while a compiler is working, a terminal can disappear while a child continues, or a wrapper can report success even though the command that mattered failed. Sending the task again may create another expensive build rather than reveal the first outcome. The useful design gives each run an identity, preserves its output and establishes completion from the process and artifact that actually matter.
This workshop follows a hypothetical release build started by a coding agent on a local computer. The build takes long enough for the user to leave the app and return from a phone. We will define what should survive that interruption and how to check a result without inventing progress. GrantTap helps inspect the correct Task, execution and available activity; it is not a general promise that every provider exposes a durable process supervisor. The examples are engineering checks you can prepare in your own environment, not measurements of an already completed build.
Define the result before starting the command
Write what a successful build must produce. Name the source revision, build configuration, target platform and expected artifact. A command finishing is one observation; an artifact existing is another; an artifact belonging to the intended revision is a third. For the workshop, choose a nonproduction fixture build with a unique output directory. That makes it possible to distinguish a newly produced artifact from an older file that happened to remain in the normal release folder. Do not let a stale file satisfy the acceptance condition after a failed compiler invocation.
Ask the agent to report the intended command and its working directory before starting work where review is appropriate. Keep environment requirements and necessary credentials separate from the visible summary. A reviewer should understand the target without receiving a dump of private environment values. The Task and execution guide helps identify the GrantTap context, while the actual build system determines how source and configuration become an artifact. This boundary keeps the phone's view useful without implying that a conversational status independently verifies the entire release pipeline.

Give the run an identity you can inspect later
Choose a run identifier and record the invocation's source, directory and start observation. A process ID is useful while that process exists, but it is not a durable global identity: operating systems can reuse it. A run record should connect the process observation, output location and eventual outcome. The exact mechanism can be a supported tool session, a build system's job ID or a small controlled runner. Do not claim that GrantTap automatically supplies an identical durable run record for every provider and arbitrary shell process.
For the fixture, make the run identifier visible in the output directory and summary. After leaving and returning, the agent should inspect that same run rather than start an unnamed replacement. If the execution changes during a handoff, record which computer owns the original process. Moving a Task does not move an operating-system process. The destination can read a supported result or request a new build deliberately, but it should not assume that a source computer's process now belongs to its own shell merely because the conversation continued there.
Distinguish silence from a stopped process
A compiler may perform substantial work between output lines. Conversely, an active-looking terminal may be waiting on input or a blocked dependency. Silence alone establishes neither healthy progress nor failure. Inspect the available process state and bounded logs. If the tool exposes only limited information, say that progress is unknown. Avoid animated status language that implies work the source has not reported. A user returning from a phone needs a meaningful observation, not a confident guess derived from how long the agent has been quiet.
In the workshop, create separate fixtures for a quiet successful command, a command waiting for input and one that exits immediately with an error. The interface or run summary should distinguish the observations it can actually make. A timeout policy can bound waiting, but a timeout does not automatically prove the underlying process stopped. Report whether the timeout affected the client wait, sent a cancellation request or observed termination. Those distinctions become important when deciding whether to inspect the original run or start another one that might compete for the same output directory.
Preserve output without treating it as the final outcome
Keep a bounded log that can be inspected after the immediate tool response ends. Capture enough context to identify the failing stage, and state when output is truncated. A live stream is useful for navigation, but it is not the same as a complete retained record. For a private project, avoid logging credentials or unrestricted environment values. Review the logging behavior before using the runner with real release material, and keep the fixture's output deliberately harmless so failure cases can be tested without exposing sensitive information.
Separate standard output and standard error when the chosen tooling makes that distinction useful, or preserve their origin if they are combined. Do not infer success from an empty error stream: many tools write diagnostics differently, and the exit outcome still matters. Likewise, a warning-looking line does not necessarily mean failure. The agent's summary should connect relevant lines to the actual command outcome. GrantTap's sources-of-activity guide explains why available transcripts and native tool details can vary; a missing old log should remain a gap rather than become a reconstructed successful result.
Check what a pipeline's status represents
A shell pipeline can contain several commands while its final reported status follows the shell's configured rules. A successful log formatter must not hide a failed compiler. Read the documented pipeline behavior for the shell actually used; do not assume Bash options apply unchanged to every shell or wrapper. The Bash pipeline manual describes Bash's status rules, including its pipefail option. The practical requirement is simpler: capture the outcome of the operation that determines whether the build succeeded.
Prepare a harmless fixture where the first stage deliberately fails and the last stage successfully formats output. Then verify that the runner reports build failure. Also test a successful compiler followed by a failing artifact-packaging stage; that is not a successful release build either. Keep the expected stage outcomes explicit. A test that only checks the wrapper's final text can miss an ignored intermediate failure. The acceptance condition should inspect the relevant exit information and artifact state, making it impossible for an unrelated successful command at the end to launder a failed build into a green summary.
Wait for the appropriate completion signal
When implementing a runner, understand the chosen process API's lifecycle. Process exit, stream closure and startup failure are different events. The Node.js child-process documentation distinguishes exit and close behavior, and describes errors during process creation. Use the event that matches the result you need, and avoid reporting final output before the relevant streams are finished. This is a specific implementation concern for a Node-based runner, not a claim that all agent tools use Node or expose the same event model.
Test a command that writes output shortly before exiting and one that cannot be started at all. The first should retain its final useful lines; the second should report a startup failure rather than wait indefinitely for a normal exit result. Keep cleanup idempotent because more than one event can be involved in an error path. The final record should have one coherent outcome. If the process API cannot establish a particular property, document the limitation instead of inventing a synthetic success state just to make every run appear to reach a tidy conclusion.
Keep working directories and output directories explicit
A relative output path can point somewhere surprising after a wrapper changes directory. Name the repository and actual working directory in the run record, and resolve artifact locations consistently. In a multi-repository Task, the same build command can be valid in one directory and meaningless in another. Ask the agent to inspect the intended manifest or project file before execution. A familiar repository name in the conversation is not evidence that the shell is currently operating inside that repository's correct checkout and configuration.
Use a separate fixture output directory for each run so concurrent builds cannot overwrite one another. If the real build system requires a shared directory, document and enforce the serialization it needs. An advisory file claim does not physically stop another process from writing. Through GrantTap, check the selected execution and available Files scope before attributing a changed artifact to the current run. The workspace guide is the interface reference; actual isolation remains an engineering property of the directories, processes and build tools used on the computer.
Make cancellation describe its real target
Stopping the agent's conversational turn may differ from terminating its child build. A supported tool cancellation may stop waiting without proving that every descendant process has ended. Define the runner's behavior and report the observed outcome. Do not promise that a single generic stop action reverses every external effect. For a fixture, use a harmless long-running process and inspect what remains after cancellation. Avoid terminating unrelated processes by name or killing every compiler on a shared machine, which could destroy another user's or agent's active work.
If the runner supports process groups or a platform-specific termination mechanism, test that mechanism under the actual operating system and toolchain. Record which child processes are within its scope. A graceful termination period and a later forced stop are different steps and should remain visible where they matter. After cancellation, inspect the output directory for partial artifacts and mark them accordingly. A half-written file should not be presented as the completed build. GrantTap can help follow the supported action, but a request sent from a phone is not itself proof of process termination.

Recover from a lost response without starting over
Simulate a connection interruption after the fixture command starts. Reopen the supported run state and inspect the original identifier. The result should distinguish running, completed, failed and unavailable where the source can establish them. If the outcome is unknown, preserve that uncertainty. A second invocation needs a deliberate decision, particularly when the original might still consume resources or write to the same target. This is the same general recovery principle behind inspecting an original message rather than blindly resending it, while the concrete process guarantees depend on the runner you actually use.
Ask the agent to explain how it reconnected to the original run. A fresh command that merely prints the previous log can establish log availability without proving the original process is still alive. Conversely, a process observation without retained output may establish activity but not diagnose a failure. Keep the evidence types separate. The message-delivery guide describes GrantTap receipt stages; those receipts establish transport facts, not arbitrary build completion. A well-designed continuation note tells the next execution where the original run lives and which observation is still needed.
Verify the artifact independently of the success message
After the run reports success, inspect the expected artifact from that run's output location. Check identity, format and the properties relevant to the task. For a web build, that may include startup and a representative route. For a signed app, the release workflow has additional platform-specific requirements. Do not generalize one artifact check into proof of every deployment target. The workshop should name exactly what is being verified and preserve the difference between a build artifact and an artifact that is actually serving users.
Use a failure fixture that leaves an old-looking output file behind. The verifier should not accept it merely because its filename matches. Tie the artifact to the run's controlled directory or available build identity, and inspect meaningful contents where appropriate. A checksum establishes byte identity, not functional correctness, so pair it with the relevant behavior check. If the source changed after the build began, clarify which revision the artifact represents. A later clean working tree does not automatically establish the inputs of an earlier process that may have read files while they were changing.
Keep a timeout budget that matches the operation
Choose timeouts from the operation's needs and observed environment, not from a universal preference for quick answers. A short client request timeout can coexist with a longer background job if the system provides a supported way to inspect it. Without that recovery path, detaching work can create an unmanageable orphan. For the workshop, document the wait interval, the job's allowed lifetime and the action at each boundary. A user should know whether they can safely leave the app and how to retrieve the eventual result.
Avoid treating every slow run as a reason to increase the timeout indefinitely. Inspect the stage and the resource conditions first. A build waiting for interactive input will not become healthy because you wait longer. A memory-constrained process may need a smaller workload or an appropriate environment rather than repeated concurrent attempts. GrantTap's usage guide helps interpret supplied observations, while unknown resource data stays unknown. The useful report explains the chosen budget and the evidence behind a changed limit, without inventing performance measurements that the source did not provide.
Review the result from a compact mobile summary
Prepare a summary containing run identity, source revision, target, final outcome, artifact location and meaningful checks. Put the detailed log behind an available reference. This lets a phone user distinguish build finished from release published without reading thousands of lines. If output was cut off or the process state could not be recovered, say so. A summary should help the user choose the next action, not replace uncertainty with a reassuring paragraph that merely repeats the agent's intention to finish the work.
When more than one run exists, list which one is authoritative for the proposed release and why. Keep superseded or canceled runs distinguishable without merging their evidence. A test passing in run A cannot automatically validate an artifact produced by run B from different source or settings. The Runtime and evidence guide describes the limits of reported results in GrantTap. Apply the same precision to your build packet: the user should be able to follow the claim to the actual run and inspect the artifact that claim concerns.
Clean up only after preserving the useful result
Once the outcome and necessary evidence are retained, remove disposable fixture output and stop owned processes that are no longer needed. Do not clear shared build directories or terminate a process solely because its name looks similar. Identify ownership and current use first. Keep the released or reviewable artifact according to the project's normal retention policy. A successful workshop should leave the computer quieter, not add a permanent collection of background watchers whose purpose is unclear to the person who owns the machine.
Record what remains running intentionally. A development server may be useful for a current review, while a finished test runner usually should exit. If cleanup fails, preserve the process identity and a bounded next step rather than concealing the leftover. This is especially important when the user previously reported excessive CPU use: starting another observer without accounting for its lifecycle can make supervision itself part of the problem. The goal is a comprehensible run and its result, with temporary machinery removed when it has served the authorized task.
Make the next long build easier to supervise
Finish by keeping the smallest reusable run contract: explicit target and inputs, identifiable process or supported job, recoverable output, meaningful final status and artifact verification. Add the failure fixtures that exposed real weaknesses. Do not create a scheduler or a new global control surface just to support one build exercise. Integrate the result into the existing workflow where possible. The improvement is that the next agent and reviewer can understand the same operation even after a quiet interval or a client interruption.
A precise request through GrantTap can now say: inspect the original run, report its observed state, retain its final output and verify its artifact before proposing another invocation. That is much more actionable than asking whether the agent is still working. It also keeps the human's attention focused on a concrete result. Silence no longer has to be interpreted as success, failure or abandonment; it becomes one observation within a run whose identity, boundaries and eventual outcome are available for the specific checks the project actually supports.