Skip to content
Back to skills

1572 Multi Entry Point Agents C1f1f27c

ASecurity

This document explains the architectural improvements made to support agents with multiple asynchronous entry points, and why the initial patterns (single-entry execution, tools-as-shared-memory) were insufficient for production use cases.

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 11, 2026
businesspythongonodetestingdebuggingapidatabase

Works with

  • api

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 1572-multi-entry-point-agents_c1f1f27c --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1572 Multi Entry Point Agents C1f1f27c?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 1572 Multi Entry Point Agents C1f1f27c
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1572-multi-entry-point-agents-c1f1f27c/badge)](https://www.skillsdirectory.com/skills/tools-only-1572-multi-entry-point-agents-c1f1f27c)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Multi-Entry-Point Agent Architecture

## Executive Summary

This document explains the architectural improvements made to support agents with multiple asynchronous entry points, and why the initial patterns (single-entry execution, tools-as-shared-memory) were insufficient for production use cases.

---

## The Problem: Real-World Agents Need Multiple Entry Points

Consider a Tier-1 support agent that must:

1. **Listen for Zendesk webhooks** - New tickets arrive asynchronously
2. **Handle API requests** - Users can query ticket status or submit follow-ups
3. **Process timer events** - Escalation checks run every 5 minutes
4. **Respond to internal events** - Other agents may delegate work

These are not sequential operations—they happen **concurrently and independently**. A webhook might fire while an API request is being processed. Two tickets might arrive simultaneously.

### Previous Architecture Limitations

The original framework had a fundamental constraint:

```python
# In Runtime (core.py:58)
class Runtime:
    def __init__(self, ...):
        self._current_run: Run | None = None  # Only ONE run at a time
```

This single `_current_run` meant:

- **No concurrent executions** - Processing one ticket blocked all others
- **No multiple entry points** - Only `entry_node` could start execution
- **State collision** - Concurrent attempts would overwrite each other's context

---

## Why Tools-as-Shared-Memory is an Anti-Pattern

A tempting workaround is using tools to manage shared state:

```python
# Anti-pattern: Using tools for state management
@tool
def get_customer_context(customer_id: str) -> dict:
    """Retrieve customer context from database."""
    return db.get_customer(customer_id)

@tool
def update_ticket_status(ticket_id: str, status: str) -> bool:
    """Update ticket status in database."""
    db.update_ticket(ticket_id, status)
    return True
```

This seems to work—tools can read/write external storage, enabling "shared state" between executions. **But this approach has serious problems:**

### 1. Race Conditions Without Isolation Control

```
Execution A: get_customer_context("cust_123") → {tickets: 5}
Execution B: get_customer_context("cust_123") → {tickets: 5}
Execution A: update_ticket_count("cust_123", 6)
Execution B: update_ticket_count("cust_123", 6)  # Should be 7!
```

Tools have no concept of isolation levels. Every call goes directly to storage with no coordination. In high-concurrency scenarios, you get:

- **Lost updates** - Changes overwrite each other
- **Dirty reads** - Reading partially-written state
- **Phantom data** - State changes between reads in the same logical operation

### 2. No Transactional Boundaries

Tools execute independently with no transaction semantics:

```python
# What if this fails halfway?
@tool
def process_refund(order_id: str) -> dict:
    mark_order_refunded(order_id)      # ✓ Succeeds
    credit_customer_account(order_id)   # ✗ Fails - network error
    send_confirmation_email(order_id)   # Never runs
    # Now order is marked refunded but customer wasn't credited!
```

With tools-as-state, there's no way to:

- Roll back partial changes
- Ensure atomic operations
- Coordinate multi-step state transitions

### 3. Invisible Dependencies Break Goal Evaluation

The goal-driven approach relies on tracking decisions and their outcomes:

```python
# Decision: "Update customer tier based on purchase history"
# Outcome: Success/Failure with observable state changes
```

When state flows through tools, the framework loses visibility:

```python
@tool
def update_customer_tier(customer_id: str) -> str:
    # What state did this read? What did it change?
    # The framework has no idea—it just sees "tool returned 'gold'"
    history = get_purchase_history(customer_id)  # Hidden read
    new_tier = calculate_tier(history)           # Hidden logic
    save_tier(customer_id, new_tier)             # Hidden write
    return new_tier
```

This breaks:

- **Outcome aggregation** - Can't track what state changed across executions
- **Constraint checking** - Can't verify invariants were maintained
- **Goal progress evaluation** - Can't correlate actions to success criteria

### 4. No Execution Correlation

When multiple entry points trigger concurrently, you need to:

- Track which execution modified which state
- Correlate related operations (e.g., webhook + follow-up API call for same ticket)
- Debug issues by tracing execution flow

Tools provide none of this. Every tool call is independent with no execution context.

### 5. Testing Becomes Impossible

With tools-as-state:

- **Unit tests** can't isolate state—every test affects global storage
- **Concurrent tests** interfere with each other
- **Mocking** requires replacing actual database/API calls

Compare to proper state management:

```python
# Isolated test - no external dependencies
memory = manager.create_memory("test-exec", "test-stream", IsolationLevel.ISOLATED)
await memory.write("key", "value")
assert await memory.read("key") == "value"
# Other tests unaffected
```

---

## The Solution: Explicit State Management Architecture

The new architecture introduces explicit state management with proper isolation:

```
┌─────────────────────────────────────────────────────┐
│                  AgentRuntime                       │
│  - Manages agent lifecycle                          │
│  - Coordinates ExecutionStreams                     │
│  - Aggregates outcomes for goal evaluation          │
├─────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐ │
│  │  Stream A   │  │  Stream B   │  │  Stream C   │ │
│  │ (webhook)   │  │   (api)     │  │  (timer)    │ │
│  │             │  │             │  │             │ │
│  │ Concurrent  │  │ Concurrent  │  │ Concurrent  │ │
│  │ Executions  │  │ Executions  │  │ Executions  │ │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘ │
│         └────────────────┼────────────────┘        │
│                          ↓                         │
│              SharedStateManager                    │
│              (Isolation Levels)                    │
│                                                    │
│              OutcomeAggregator                     │
│              (Cross-Stream Goals)                  │
└─────────────────────────────────────────────────────┘
```

### Key Components

#### 1. SharedStateManager with Isolation Levels

```python
class IsolationLevel(Enum):
    ISOLATED = "isolated"      # Private state per execution
    SHARED = "shared"          # Visible across executions (eventual consistency)
    SYNCHRONIZED = "synchronized"  # Shared with write locks (strong consistency)
```

Each execution gets explicit control over state visibility:

```python
# Execution-local state (safe from interference)
await memory.write("scratch_data", value, scope=StateScope.EXECUTION)

# Stream-shared state (visible to all executions in this stream)
await memory.write("stream_counter", count, scope=StateScope.STREAM)

# Global state (visible everywhere, use carefully)
await memory.write("system_config", config, scope=StateScope.GLOBAL)
```

#### 2. StreamRuntime with Execution Tracking

```python
class StreamRuntime:
    def __init__(self, stream_id, storage, outcome_aggregator):
        # Track runs by execution_id, not single _current_run
        self._runs: dict[str, Run] = {}
```

Now multiple executions can run concurrently without collision:

```python
# Execution A
runtime.start_run(execution_id="exec-A", goal_id="support")
runtime.decide(execution_id="exec-A", intent="classify ticket", ...)

# Execution B (concurrent, no collision)
runtime.start_run(execution_id="exec-B", goal_id="support")
runtime.decide(execution_id="exec-B", intent="classify ticket", ...)
```

#### 3. OutcomeAggregator for Cross-Stream Goals

```python
class OutcomeAggregator:
    def record_decision(self, stream_id, execution_id, decision) -> None
    def record_outcome(self, stream_id, execution_id, decision_id, outcome) -> None
    async def evaluate_goal_progress(self) -> dict
```

The framework now tracks all decisions across all streams, enabling:

- Unified goal progress evaluation
- Constraint violation detection across executions
- Success criteria tracking with proper attribution

#### 4. EventBus for Coordination

```python
# Stream A publishes
await bus.publish(AgentEvent(
    type=EventType.EXECUTION_COMPLETED,
    stream_id="webhook",
    execution_id="exec-123",
    data={"ticket_resolved": True},
))

# Stream B subscribes
bus.subscribe(
    event_types=[EventType.EXECUTION_COMPLETED],
    handler=on_ticket_resolved,
    filter_stream="webhook",
)
```

Streams can coordinate without tight coupling or shared mutable state.

---

## When Tools ARE Appropriate

Tools remain the right choice for:

1. **External system integration** - Calling APIs, databases, services
2. **Side effects** - Sending emails, creating resources
3. **Data retrieval** - Fetching information needed for decisions

The key distinction:

| Use Case                             | Correct Approach                  |
| ------------------------------------ | --------------------------------- |
| Coordinate between executions        | SharedStateManager                |
| Track decision outcomes              | StreamRuntime + OutcomeAggregator |
| Call external API                    | Tool                              |
| Persist business data                | Tool (to external storage)        |
| Share scratch state during execution | StreamMemory                      |
| Publish events to other streams      | EventBus                          |

---

## Migration Guide

### Before (Anti-Pattern)

```python
# tools.py - State hidden in tools
@tool
def get_processing_count() -> int:
    return redis.get("processing_count") or 0

@tool
def increment_processing_count() -> int:
    return redis.incr("processing_count")
```

### After (Proper Architecture)

```python
# In node execution
async def execute(self, context, memory):
    # Read from managed state
    count = await memory.read("processing_count") or 0

    # Update with proper isolation
    await memory.write(
        "processing_count",
        count + 1,
        scope=StateScope.STREAM,  # Explicit scope
    )
```

---

## Summary

| Aspect        | Tools-as-State   | Explicit State Management |
| ------------- | ---------------- | ------------------------- |
| Concurrency   | Race conditions  | Isolation levels          |
| Transactions  | None             | Execution-scoped          |
| Visibility    | Hidden           | Observable                |
| Testing       | Requires mocking | Isolated by design        |
| Goal tracking | Broken           | Full attribution          |
| Debugging     | Opaque           | Traceable                 |

The multi-entry-point architecture doesn't just enable concurrent execution—it provides the foundation for **reliable, observable, goal-driven agents** that can operate safely in production environments.

---

## References

- [core/framework/runtime/agent_runtime.py](../../core/framework/runtime/agent_runtime.py) - AgentRuntime implementation
- [core/framework/runtime/shared_state.py](../../core/framework/runtime/shared_state.py) - SharedStateManager
- [core/framework/runtime/outcome_aggregator.py](../../core/framework/runtime/outcome_aggregator.py) - Cross-stream goal evaluation
- [core/framework/runtime/tests/test_agent_runtime.py](../../core/framework/runtime/tests/test_agent_runtime.py) - Test examples

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.