How Apache Maka Manages Agent Lifecycle: A Deep Dive into RelayAgent
Apache Maka manages agent lifecycle through a deterministic state machine implemented in RelayAgent that orchestrates construction, setup, execution, cancellation teardown, and final cleanup to ensure isolated command execution never leaves orphaned processes or resources.
The apache/maka repository provides a hardened evaluation harness where agents execute untrusted commands inside isolated environments. Understanding the Maka agent lifecycle reveals how the framework guarantees resource cleanup, signal handling, and deterministic termination even when subjects misbehave or trials abort unexpectedly.
Construction and Initialization
Every agent lifecycle begins in RelayAgent.__init__ within packages/eval/harbor/relay_agent.py (lines 86–103). The constructor stores relay connection parameters—including host, port, and authentication token—and validates the teardown timeout configuration that governs graceful shutdown attempts. This initialization phase establishes the agent's identity and timeout policies before any network activity occurs.
from packages.eval.harbor.relay_agent import RelayAgent
agent = RelayAgent(
relay_host="127.0.0.1",
relay_port=5000,
relay_token="abc123",
teardown_timeout_ms=5000,
)
await agent.setup(env) # No-op for eval agents
await agent.run(
instruction="run my-test",
environment=env, # An object implementing BaseEnvironment
context={}, # Optional context passed through the relay
)
The Setup Phase
The RelayAgent.setup method (lines 111–113) serves as a contract hook defined by the abstract BaseAgent class. While the eval implementation leaves this as a no‑op, the method exists so specialized agents can perform environment preparation, credential validation, or resource pre‑allocation before the main execution loop begins. This design pattern ensures all Maka agent lifecycle implementations follow a consistent preparation protocol.
Execution Flow in RelayAgent.run
The core orchestration happens inside RelayAgent.run (lines 114–182), which implements the "run‑execute‑report‑verify" protocol through several distinct phases.
Connection and Validation
First, the agent opens an asynchronous TCP connection to the relay host using asyncio.open_connection. It resolves the task's working directory inside the sandbox and invokes _require_constrained_subject to verify the subject operates under the correct network namespace and capability set before execution starts. This constraint check prevents privilege escalation before the agent sends the ready message containing the token, instruction, and current working directory.
Command Preparation and Launch
Upon receiving the execute request via _receive and _require_message, the agent builds a safe command string using _prepare_command. This helper injects credentials and constructs the execution context, then the agent launches the subject through environment.exec.
# Inside the agent – how a subject is prepared and executed
command = await _prepare_command(
environment, # The sandbox environment
request, # JSON from the relay containing `command`, `args`, etc.
token="abc123",
scope_path="/logs/agent/.maka-eval-abc123.pid",
)
# Launch the subject inside the container
execution = asyncio.create_task(environment.exec(command, cwd=working_dir))
Concurrent Monitoring and Reporting
During execution, the agent simultaneously waits for either the subject to finish naturally or a verify control message from the relay. Once the subject completes, _persist_subject_outputs captures stdout and stderr artifacts, while _project_result and _decode_result_carrier decode the result payload. The agent then transmits an executed message containing the exit code, output streams, and diagnostic information, followed by blocking on the verify message to complete the round‑trip handshake.
Cancellation and Teardown Handling
When the coroutine receives a cancellation signal—triggered by trial abortion or timeout—the Maka agent lifecycle enters its critical termination path (lines 183–225). The agent determines whether the subject remains active and invokes _settle_or_destroy to attempt graceful shutdown via SIGTERM followed by SIGKILL within the configured timeout window.
# Graceful termination path (triggered by cancellation)
result = await _settle_or_destroy(
environment,
cwd=working_dir,
scope_path="/logs/agent/.maka-eval-abc123.pid",
execution=execution,
timeout=5.0,
)
If the subject refuses to terminate gracefully, the agent forcibly stops the container and dispatches a final executed message indicating whether the shutdown was normal or forced. This ensures runaway subjects cannot survive a cancelled trial.
Cleanup and Resource Management
Regardless of exit path—successful completion or cancellation—the agent executes a deterministic cleanup sequence (lines 226–274). It cancels any pending decision tasks, removes temporary scope files and environment artifacts from the container using _quiesce_scope, and gracefully closes the network writer. These steps ensure no stray files, zombie processes, or open sockets persist after the agent finishes, implementing the cleanup guarantee required by the BaseAgent contract.
Summary
- Initialization occurs in
RelayAgent.__init__, validating timeouts and storing relay connection details inpackages/eval/harbor/relay_agent.py. - Setup follows the
BaseAgentcontract throughRelayAgent.setup, providing a hook for preparation logic even when unused by eval agents. - Execution runs through
RelayAgent.run, implementing the "run‑execute‑report‑verify" state machine with concurrent subject monitoring and relay communication. - Cancellation triggers
_settle_or_destroyto deliver SIGTERM/SIGKILL cascades and forcibly destroy containers that exceed the teardown timeout. - Cleanup removes all temporary scopes, cancels pending tasks, and closes network connections to prevent resource leakage.
Frequently Asked Questions
What is the base class for Maka agents?
All concrete agents inherit from BaseAgent, defined in the harbor or pier agents base module. This abstract class establishes the setup and run interface contract that RelayAgent implements in packages/eval/harbor/relay_agent.py.
How does RelayAgent handle runaway processes?
When a subject refuses to terminate gracefully, _settle_or_destroy sends SIGTERM, waits for the configured timeout, escalates to SIGKILL, and finally forcibly destroys the container if the process group remains active. This multi-stage escalation prevents zombie processes from surviving agent cancellation.
What happens when a Maka agent is cancelled mid-execution?
The cancellation handler in RelayAgent.run (lines 183–225) intercepts the asyncio.CancelledError, checks subject status, initiates the settlement protocol via _settle_or_destroy, transmits a termination status message to the relay, and proceeds to cleanup. This ensures the relay receives notification even during abnormal termination.
Where is the agent lifecycle state machine defined?
The deterministic state machine—progressing from init → setup → run → (normal completion or cancellation) → cleanup—is implemented entirely within the RelayAgent class in packages/eval/harbor/relay_agent.py, with state transitions managed through Python's asyncio event loop and structured exception handling.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →