Agent Startup Architecture: Runtime Design for Multi-Agent Extension
This article examines how to design an Agent system from startup to multi-agent extension. It separates runtime-mode routing from component assembly, process-level infrastructure from session-level state, and presents a unified runtime for interactive, headless, remote, background, and resumed execution. It then covers tool capability layers, execution-boundary permissions, explicit session and task state, protocol-based delegation with least-privilege inheritance, extension registration, and decision-chain observability. The goal is to show how Agent systems can manage increasing complexity while keeping boundaries clear, behavior explainable, failures recoverable, and capabilities extensible.
In the early stages of an Agent system, it is easy to develop a misleading impression: once model calls, tool execution, and a loop are connected, the core architecture is complete.
This kind of implementation can indeed produce a demo quickly. But as the system gradually adds tools, permissions, runtime modes, background tasks, session recovery, and multi-agent collaboration, problems surface rapidly:
- The main loop begins to carry all business decisions.
- Different runtime modes define their own behaviors.
- Tools share state, causing mutual contamination.
- Foreground sessions, background tasks, and remote requests interfere with one another.
- Permission logic is scattered across tool implementations, prompts, and callers.
- Extension modules are integrated through many special cases, eventually forming a hard-to-maintain network of branches.
Therefore, whether an Agent can evolve over the long term depends not only on model capability but also on the runtime design around the model. A mature Agent system is essentially a complexity management mechanism: it must decide which logic must be handled up front, which state must be isolated, which capabilities should be abstracted into protocols, and which changes should be absorbed only through an extension layer.
This article discusses a general design approach across the full path from startup to multi-agent extension.
1. Core Tasks of the Startup Layer: Route First, Assemble Later
In many systems, the entry function gradually becomes a “super initializer”: it reads all configuration, creates all clients, registers all tools, initializes all background services, and only then determines what the user actually wants to do.
The problem with this approach is that the entry layer simultaneously handles four responsibilities: identification, configuration, resource creation, and business execution. As features grow, any new scenario may require modifying the main entry point, making startup behavior increasingly unpredictable.
A more reasonable startup process should be divided into three phases:
Command or request enters↓Runtime mode identification↓Process-level environment initialization↓Session-level context assembly↓Enter the unified runtime
1.1 Determine the Runtime Mode First
Common runtime modes include:
- Local interactive sessions;
- Headless or batch execution;
- Remote request-driven execution;
- Background tasks;
- Session recovery;
- Callable interfaces for other programs.
Although these modes share model, tool, and permission capabilities, their input/output methods, lifecycles, and error-handling mechanisms are different.
Therefore, the startup layer must first perform “routing” rather than “starting all components.” The routing result can be abstracted into a runtime configuration:
RuntimeMode├── Interactive├── Headless├── Remote├── Background└── Resume
After routing, each mode assembles only the capabilities it needs. For example, interactive mode may need terminal rendering, input reading, and interrupt handling, while background mode focuses more on task-state persistence, timeout control, and retry mechanisms.
This approach provides three benefits.
First, it reduces startup cost. There is no need to create full interactive resources for a simple headless call.
Second, it prevents modes from contaminating one another. Terminal state, background task state, and remote request context should not be shared by default.
Third, it preserves boundaries for future extension. When adding a new runtime mode, only a new routing strategy and corresponding assembler are needed, rather than changes to all business logic.
1.2 Separate Process-Level Initialization from Session-Level Initialization
One of the most easily overlooked design decisions in the startup layer is distinguishing between resources that need to be initialized only once per process and resources that must be independently owned by each session.
Process-level resources typically include:
- Base configuration loading;
- Logging and monitoring initialization;
- Environment variable parsing;
- Global cleanup callbacks;
- Remote configuration synchronization;
- Runtime version and capability checks.
Session-level resources include:
- The current working directory;
- Session identifier;
- Message history;
- Current model configuration;
- Tool authorization scope;
- Cancellation signals;
- Temporary files and task state.
The relationship can be represented as follows:
ProcessContext├── Configuration├── Telemetry├── CleanupRegistry└── CapabilityRegistrySessionContext├── SessionId├── ConversationState├── WorkingDirectory├── PermissionScope├── CancellationToken└── ToolRuntime
Mixing the two creates typical problems: one session changes configuration and other sessions change with it; a background task exits and mistakenly cleans up foreground resources; concurrent users experience context cross-contamination.
The correct approach is to let the process context provide only stable infrastructure, while the session context carries business state. Session objects should be passed explicitly as much as possible, avoiding reliance on many implicit global variables.
2. Unified Runtime: Shared Semantics Across Entry Points
Runtime modes can differ, but the core execution semantics should remain consistent. A unified runtime means that whether a request comes from an interactive interface, a remote call, or a background task, it goes through a similar processing flow:
Input normalization↓Context construction↓Policy checks↓Model decision↓Tool invocation↓Result normalization↓State update and output
A unified runtime does not mean that all modes use exactly the same interface. It requires consistency in the following concepts:
- How messages are represented;
- How tool calls are described;
- How permissions are checked;
- How errors are classified;
- How tasks are cancelled;
- How state is recorded;
- How results are returned.
If each entry point has its own loop, even if the functionality is identical at the beginning, differences will gradually emerge. For example, interactive mode supports permission confirmation, while batch mode bypasses permission checks; background tasks support retries, while remote requests lack timeout control. These differences eventually become system behaviors that are difficult to explain.
3. Tool System: From Function Collection to Controlled Capability Layer
As the number of tools grows, the most dangerous approach is to register all functions directly with the model. A tool is not merely a function; it also includes input constraints, permission requirements, side effects, timeouts, resource consumption, and audit information.
A more complete tool description should include at least:
ToolDefinition├── Name├── Description├── InputSchema├── PermissionRequirement├── SideEffectLevel├── TimeoutPolicy├── RetryPolicy└── AuditMetadata
3.1 Separate Tool Discovery from Tool Execution
Whether the model “knows that a tool exists” should not be equivalent to whether the system allows it to execute that tool.
The tool flow can therefore be split into two steps:
Candidate tool set↓Filter by session capabilities↓Generate model-visible descriptions↓Receive invocation request↓Perform permission validation again↓Execute
The need for “validation again” must be emphasized. The model seeing a tool description does not mean the invocation is inherently trustworthy. Permission checks should occur before actual execution and must not rely only on prompt constraints.
3.2 Standardize Tool Results
Different tools may return text, structured data, file changes, diagnostic information, or asynchronous task identifiers. If these results are directly concatenated into message history, the main loop becomes full of type checks.
A unified result model can be defined:
ToolResult├── Status├── Content├── StructuredData├── Artifacts├── Error└── Metadata
In this way, upper layers only need to handle stable states such as “success, failure, partial success, and waiting for continuation,” without needing to understand each tool’s internal implementation.
3.3 Isolate Tool Side Effects
Tools can be layered according to the degree of side effects:
- Read-only tools: querying files, reading configuration, analyzing code;
- Low-risk writes: creating temporary files, generating patches;
- High-risk operations: modifying core files, executing external commands, publishing changes;
- Long-running tasks: builds, tests, deployments, or batch processing.
Different levels should use different authorization policies, timeout policies, and audit granularity. In this way, the permission system is no longer a set of conditional checks scattered across tool functions; it becomes part of the runtime.
4. Permission Design: Place the Security Boundary in the Runtime
Simply telling the model through prompts “do not perform dangerous operations” cannot constitute a reliable security boundary. Prompts provide behavioral guidance, while the permission system provides execution control. The two have different responsibilities.
Permission decisions should consider at least:
- The current user or caller;
- The current session;
- The working directory;
- The target resource;
- The tool’s side-effect level;
- Whether human confirmation is required;
- Whether background execution is allowed;
- Whether resource quotas are exceeded.
The permission decision can be abstracted as:
Decision = Policy(Principal,Session,Tool,Resource,Context)
The return result can be:
AllowDenyAskForConfirmationAllowWithRestriction
“Allow with restriction” is especially important. For example, allow reading a specified directory but prohibit access to sensitive directories; allow modifying workspace files but prohibit modifying configuration files; allow running tests but limit execution time and concurrency.
Permission policies should be managed centrally as much as possible. Tools themselves can declare requirements, but the final decision should be made by a unified policy layer to avoid inconsistent security standards across tools.
5. Sessions and Background Tasks: State Must Be Explicit
Agent systems usually have two types of state at the same time.
One is conversation state, such as message history, current goals, model context, and the tool invocation chain.
The other is task state, such as an ongoing build, an external task that is waiting, retry counts, and interruption reasons.
These two types of state cannot simply be mixed into one object. A conversation may end while a background task is still running; a background task failure does not necessarily mean the entire session is invalid.
Tasks can be modeled as independent entities:
Task├── TaskId├── ParentSessionId├── Status├── Input├── Progress├── Result├── Error├── StartedAt└── FinishedAt
A session associates with background execution through a task identifier rather than directly holding an execution thread. This supports:
- Tasks continuing to run after the session disconnects;
- Querying task status after reconnecting;
- Cancelling an individual task;
- Retrying a task;
- Recording task audit information in a unified way.
Cancellation mechanisms should also run through the entire call chain. It is not enough to stop only the model request while allowing the tool process to continue running; it is also not enough to close only the interface without notifying background tasks. A complete cancellation signal should be propagated to the model, tools, subtasks, and resource cleanup layer.
6. Multi-Agent Extension: Not Copying Multiple Main Loops
When a system needs multiple Agents to collaborate, the most common mistake is to copy multiple complete main loops and let them communicate through shared variables or temporary messages.
The problems with this design are:
- Each Agent has a different state format;
- Tool permissions are difficult to unify;
- Task failures cannot be handled centrally;
- Message paths are difficult to trace;
- Scheduling relationships depend on many special cases.
A more robust approach is to build multi-agent capabilities on top of the unified runtime. Each Agent is simply a runtime unit with a different role, context, and capability set.
AgentRuntime├── Identity├── Role├── Context├── CapabilitySet├── PolicyScope├── MemoryScope└── ExecutionState
6.1 Distinguish Agents by Role and Capability
Different Agents do not necessarily need different underlying loops. They can differ along the following dimensions:
- System instructions;
- Available tool sets;
- Accessible resource scopes;
- Task objectives;
- Output formats;
- Maximum execution depth;
- Whether task delegation is allowed.
For example, an analysis Agent may have only read-only tools; a modification Agent can generate changes; a review Agent checks results but does not directly write to resources.
6.2 Delegation Should Be an Explicit Protocol
When one Agent calls another, it should not directly share all internal state. Instead, it should pass information through a structured task protocol:
DelegationRequest├── RequestId├── ParentAgentId├── ChildAgentId├── Objective├── InputContext├── Constraints├── ExpectedOutput└── Deadline
The child Agent should also return a structured result, including conclusions, evidence, artifacts, risks, and unfinished items.
This approach helps implement:
- Call-chain tracing;
- Timeout control;
- Permission inheritance and reduction;
- Subtask retries;
- Result auditing;
- Concurrent multi-agent scheduling.
6.3 Permissions Should Shrink by Default, Not Inherit Without Limit
The capabilities owned by a parent Agent do not mean that a child Agent can inherit all of them. Delegation should explicitly pass a minimum permission set:
ChildPermissions ⊆ ParentPermissions
For example, the parent Agent may modify the workspace, but when delegating to a review Agent, it passes only read and analysis permissions. In this way, even if the child Agent behaves unexpectedly, the impact can be limited to a bounded scope.
7. Extension Layer Design: Absorb Change Through Registration and Protocols
When a system needs to support new models, new tools, new storage methods, or new interactive interfaces, directly modifying the core loop is the least desirable option.
Changes can be concentrated into several extension points:
ModelProviderToolProviderMemoryProviderPolicyProviderTransportProviderStorageProvider
The core runtime depends only on abstract protocols and does not care about concrete implementations. Extension modules register their own capabilities and participate in assembly through capability descriptions.
The extension layer should also provide lifecycle management:
initializevalidatestartstopcleanup
Among these, validate should not be omitted. Many systems discover only during runtime that an extension lacks necessary configuration, making errors difficult to locate. Performing capability checks during startup exposes problems earlier.
8. Observability: Record the Decision Chain, Not Just Error Logs
The difficulty of Agent systems is that the final result is often produced by multiple steps. Simply recording “request failed” cannot answer:
- Why the model chose a particular tool;
- Why a tool was rejected;
- Which policy caused a wait for confirmation;
- Why a child Agent timed out;
- Which step changed session state.
Therefore, logging and tracing should be designed around the decision chain. At minimum, record:
- Session identifier;
- Task identifier;
- Agent identifier;
- Model request and response summaries;
- Tool invocation parameter summaries;
- Permission decisions;
- State transitions;
- Retry and cancellation reasons;
- Resource consumption information.
For sensitive data, use redaction, summaries, or tiered storage to avoid introducing new data risks in the name of observability.
9. Principles Most Worth Adopting for Self-Built Agent Systems
Taken together, the most valuable lessons from mature Agent architectures are not any specific implementation, but the following systemic principles.
First, the entry layer is responsible only for identification and assembly, not for carrying all business logic.
Second, process-level resources, session-level state, and task-level state must be separated.
Third, different runtime modes can have different shells, but they should share unified runtime semantics.
Fourth, tools must have descriptions, permissions, lifecycles, and result models at the same time.
Fifth, permission checks must be located at the execution boundary, not only in the prompt layer.
Sixth, multi-agent collaboration should be implemented through explicit task protocols rather than shared internal state.
Seventh, child Agent capabilities should shrink by default, following the principle of least privilege.
Eighth, extension capabilities should be integrated through protocols and registration mechanisms, avoiding continuous special-case additions to core logic.
Ninth, observability should cover the complete decision chain, not just final errors.
Tenth, any new feature should first answer one question: which kind of state, boundary, or lifecycle does it add? If the answer is unclear, the feature should not be rushed into the main loop.
The real engineering difficulty of Agent systems is never getting the model to complete a single task. It is keeping boundaries clear, behavior explainable, failures recoverable, and capabilities extensible as complexity continues to grow. The startup layer determines how the system enters the running state; the runtime determines how complexity is absorbed; and the extension layer determines whether future changes fall outside protocol boundaries or continue to intrude into the core. Only by designing these three layers well can an Agent evolve from a one-off demo into a maintainable engineering system.
