Skip to content

lapc506/agentic-core

Repository files navigation

agentic-core

Production-ready Python 3.12+ library for AI agent orchestration. Designed as a shared dependency for any startup integrating autonomous agents into their Kubernetes infrastructure via sidecar injection or standalone deployment.

This library contains NO domain-specific graphs or business logic. All graphs live inside each project's own monorepo.

Architecture

Built on Explicit Architecture (Hexagonal + DDD + CQRS). All arrows point inward. Infrastructure depends on domain-defined ports, never the reverse.

Layered Architecture

graph TB
    subgraph PRIMARY["PRIMARY ADAPTERS (Driving)"]
        WS["WebSocket Adapter"]
        GRPC["gRPC Adapter"]
        CLI["CLI Adapter (future)"]
    end

    subgraph APP["APPLICATION LAYER"]
        direction TB
        CMD["Commands: HandleMessage, CreateSession,<br/>ResumeHITL, ExecuteRoadmap, OptimizeSkill"]
        QRY["Queries: GetSession, ListPersonas, GetSLOStatus"]
        PORTS["Ports: MemoryPort, SessionPort, EmbeddingPort,<br/>GraphStorePort, ToolPort, TracingPort,<br/>MetricsPort, CostTrackingPort, GraphOrchestrationPort, AlertPort"]
        MW["Middleware: Tracing, Auth, RateLimit, PII, Metrics"]
        SVC["Services: GSDSequencer, SuperpowersFlow, AutoResearchLoop"]
    end

    subgraph DOMAIN["DOMAIN LAYER (pure, zero dependencies)"]
        ENT["Entities: Session, Persona, Skill, Roadmap"]
        VO["Value Objects: AgentMessage, Checkpoint, SLOTarget, EvalResult"]
        EVT["Domain Events: MessageProcessed, SessionCreated,<br/>SLOBreached, SkillOptimized, ToolDegraded,<br/>HumanEscalationRequested, ErrorBudgetExhausted"]
        DSVC["Domain Services: RoutingService, EscalationService, EvalScoring"]
    end

    subgraph SECONDARY["SECONDARY ADAPTERS (Driven)"]
        REDIS["Redis"]
        PG["PostgreSQL"]
        PGV["pgvector"]
        FDB["FalkorDB"]
        LFUSE["Langfuse"]
        OTEL["OpenTelemetry"]
        MCP["MCP Bridge"]
        LG["LangGraph"]
    end

    WS & GRPC & CLI -->|"calls Ports"| APP
    APP -->|"uses"| DOMAIN
    APP -.->|"depends on Port interfaces<br/>(dependency inversion)"| SECONDARY

    style PRIMARY fill:#4A90D9,color:#fff
    style APP fill:#7B68EE,color:#fff
    style DOMAIN fill:#2ECC71,color:#fff
    style SECONDARY fill:#E67E22,color:#fff
Loading

Hexagonal Ports & Adapters

graph LR
    subgraph DRIVING["Driving Side (Primary)"]
        Flutter["Flutter Client<br/>(WebSocket)"]
        NestJS["NestJS / Serverpod<br/>(gRPC)"]
    end

    subgraph CORE["Application Core"]
        direction TB
        P_IN["Inbound Ports"]
        HANDLERS["Command & Query Handlers"]
        MIDDLEWARE["Middleware Chain"]
        P_OUT["Outbound Ports"]
    end

    subgraph DRIVEN["Driven Side (Secondary)"]
        Redis["Redis"]
        Postgres["PostgreSQL + pgvector"]
        FalkorDB["FalkorDB"]
        MCPServers["MCP Servers"]
        OTel["OpenTelemetry"]
        Langfuse["Langfuse"]
        LangGraph["LangGraph"]
    end

    Flutter -->|WebSocket| P_IN
    NestJS -->|gRPC| P_IN
    P_IN --> MIDDLEWARE --> HANDLERS
    HANDLERS --> P_OUT
    P_OUT -->|MemoryPort| Redis
    P_OUT -->|SessionPort + EmbeddingPort| Postgres
    P_OUT -->|GraphStorePort| FalkorDB
    P_OUT -->|ToolPort| MCPServers
    P_OUT -->|TracingPort + MetricsPort| OTel
    P_OUT -->|CostTrackingPort| Langfuse
    P_OUT -->|GraphOrchestrationPort| LangGraph

    style CORE fill:#2ECC71,color:#fff
    style DRIVING fill:#4A90D9,color:#fff
    style DRIVEN fill:#E67E22,color:#fff
Loading

Message Flow (Request Lifecycle)

sequenceDiagram
    participant Client as Flutter Client
    participant WS as WebSocket Adapter
    participant MW as Middleware Chain
    participant CMD as HandleMessageHandler
    participant Kernel as AgentKernel
    participant Graph as LangGraph
    participant Tool as MCP Tool
    participant Mem as Redis (MemoryPort)

    Client->>WS: {"type": "message", "content": "..."}
    WS->>WS: Construct & validate AgentMessage (Pydantic)
    WS->>MW: AgentMessage

    Note over MW: Tracing -> Auth -> RateLimit -> PII -> Metrics

    MW->>CMD: Validated AgentMessage
    CMD->>Mem: store_message()
    CMD->>Kernel: route(persona_id)
    Kernel->>Graph: astream_events(input, thread_id)

    loop Graph Execution
        Graph->>Tool: execute("mcp_zendesk_create_ticket", args)
        Tool-->>Graph: ToolResult
    end

    Graph-->>CMD: StreamEvent (token)
    CMD-->>MW: AgentMessage (stream_token)
    MW-->>WS: Apply PII redaction on output
    WS-->>Client: {"type": "stream_token", "token": "..."}

    Note over CMD: publish(MessageProcessed) -> EventBus
Loading

CQRS: Commands vs Queries

graph LR
    subgraph Commands["Commands (Write Side)"]
        C1["HandleMessage"]
        C2["CreateSession"]
        C3["ResumeHITL"]
        C4["ExecuteRoadmap"]
        C5["OptimizeSkill"]
    end

    subgraph Queries["Queries (Read Side)"]
        Q1["GetSession"]
        Q2["ListPersonas"]
        Q3["GetSLOStatus"]
    end

    subgraph Events["Domain Events"]
        E1["MessageProcessed"]
        E2["SessionCreated"]
        E3["SLOBreached"]
        E4["ToolDegraded"]
    end

    PA["Primary Adapters<br/>(WebSocket / gRPC)"]

    PA -->|"write operations"| Commands
    PA -->|"read operations"| Queries
    Commands -->|"publish"| Events
    Events -->|"notify"| HANDLERS["Event Handlers<br/>(via EventBus)"]

    style Commands fill:#E74C3C,color:#fff
    style Queries fill:#3498DB,color:#fff
    style Events fill:#F39C12,color:#fff
Loading

Key Features

  • Hybrid Transport -- WebSocket (bidirectional, streaming, ElevenLabs voice) + gRPC (backend-to-sidecar)
  • LangGraph Orchestration -- Pluggable graph templates: ReAct, Plan-and-Execute, Reflexion, LLM-Compiler, Supervisor, Orchestrator
  • Unified Memory -- Redis + PostgreSQL + pgvector + FalkorDB (all required)
  • MCP Bridge -- Discover and execute tools from MCP servers with phantom tool prevention (OpenClaw #50131 mitigation)
  • Multimodal RAG -- Gemini Embedding 2 (text + image + audio + video + PDF in one vector space) with Matryoshka dimension control
  • Meta-Orchestration -- GSD Sequencer, Superpowers Flow, Auto Research Loop for self-improving agents
  • Hybrid Persona System -- YAML config (PM-editable) + Python code (engineer override)
  • LLM Model Cascading -- Runtime -> Persona -> Sub-agent inheritance with per-level override
  • Full SRE Observability -- OpenTelemetry + Prometheus + Loki + Tempo + Grafana + Langfuse + Alertmanager
  • Kubernetes-Native -- Dual deployment: standalone or sidecar, single Helm chart

Meta-Orchestration: GSD + Superpowers + Auto Research

Three pillars for autonomous agent development cycles:

graph TB
    subgraph SUPERPOWERS["SuperpowersFlow (Full Engineering Cycle)"]
        direction TB
        SP1["Map Terrain<br/><i>analyze codebase</i>"]
        SP2["Research Gaps<br/><i>security, UX, impl</i>"]
        SP3["Brainstorm 2-3<br/>Approaches"]
        SP4{{"HITL: User<br/>Chooses Approach"}}
        SP5["Generate Spec"]
        SP6["Create Roadmap"]
        SP7{{"HITL: User<br/>Approves Roadmap"}}
        SP1 --> SP2 --> SP3 --> SP4 --> SP5 --> SP6 --> SP7
    end

    subgraph GSD["GSD Sequencer (Spec-Driven Execution)"]
        direction TB
        G1["Phase 1: Task A"]
        G2["Verify A"]
        G3["Phase 1: Task B"]
        G4["Verify B"]
        G5["Gate: Phase 1 complete?"]
        G6["Phase 2: Task C<br/><i>(fresh context,<br/>only summary of A+B)</i>"]
        G1 --> G2 --> G3 --> G4 --> G5 -->|pass| G6
        G5 -->|fail| G1
    end

    subgraph AUTO["AutoResearch Loop (Skill Self-Improvement)"]
        direction TB
        A1["Batch Execute<br/>Skill x10"]
        A2["Evaluate with<br/>Binary Rules"]
        A3{"Score<br/>improved?"}
        A4["Mutate<br/>Instructions"]
        A5["Keep Best<br/>Version"]
        A1 --> A2 --> A3
        A3 -->|no| A4 --> A1
        A3 -->|yes| A5 --> A1
        A3 -->|perfect| DONE["Done"]
    end

    SP7 -->|"approved"| GSD
    GSD -->|"has skills to optimize"| AUTO

    style SUPERPOWERS fill:#8E44AD,color:#fff
    style GSD fill:#2980B9,color:#fff
    style AUTO fill:#27AE60,color:#fff
Loading

Graph Template Decision Tree

graph TD
    START{"Does your agent<br/>use tools?"} -->|No| DIRECT["Direct LLM<br/><i>no graph needed</i>"]
    START -->|Yes| PLAN{"Needs to plan<br/>multiple steps<br/>before acting?"}
    PLAN -->|No| RE["react<br/><i>default, 80% of cases</i>"]
    PLAN -->|Yes| INDEP{"Are steps<br/>independent?"}
    INDEP -->|Yes| LLC["llm-compiler<br/><i>parallel execution</i>"]
    INDEP -->|No| PE["plan-and-execute"]

    QUALITY{"Output quality<br/>justifies retry loops?<br/><i>(orthogonal)</i>"} -->|Yes| REF["reflexion<br/><i>wraps any template above</i>"]

    MULTI{"Multiple personas<br/>that collaborate?"} -->|Yes| SUP["supervisor"]

    AUTONOMOUS{"Full autonomous<br/>dev cycles?"} -->|Yes| ORCH["orchestrator<br/><i>GSD + Superpowers<br/>+ Auto Research</i>"]

    style RE fill:#2ECC71,color:#fff
    style PE fill:#3498DB,color:#fff
    style LLC fill:#9B59B6,color:#fff
    style REF fill:#E67E22,color:#fff
    style SUP fill:#E74C3C,color:#fff
    style ORCH fill:#1ABC9C,color:#fff
    style DIRECT fill:#95A5A6,color:#fff
Loading

Quick Start

pip install agentic-core

1. Define a Persona (YAML)

# agents/support-agent.yaml
name: support-agent
role: "Customer support specialist"
graph_template: react
tools:
  - mcp_zendesk_*
  - rag_search
escalation_rules:
  - condition: "sentiment < -0.7"
    target: "human"
    priority: "urgent"
model_config:
  provider: "anthropic"
  model: "claude-sonnet-4-6"
  temperature: 0.3
slo_targets:
  latency_p99_ms: 5000
  success_rate: 0.995

2. Override with Code (Optional)

from agentic_core.graph_templates.base import BaseAgentGraph

@agent_persona("support-agent")
class SupportGraph(BaseAgentGraph):
    def build_graph(self):
        # Custom LangGraph logic -- overrides YAML graph_template
        ...

3. Start the Runtime

from agentic_core.config.settings import AgenticSettings
from agentic_core.runtime import AgentRuntime

settings = AgenticSettings(
    redis_url="redis://localhost:6379",
    postgres_dsn="postgresql://localhost:5432/agentic",
    falkordb_url="redis://localhost:6380",
)

runtime = AgentRuntime(settings)
await runtime.start()  # WebSocket :8765 + gRPC :50051

4. Connect from Flutter

final channel = WebSocketChannel.connect(Uri.parse('ws://localhost:8765'));

// Create session
channel.sink.add(jsonEncode({
  'type': 'create_session',
  'persona_id': 'support-agent',
  'user_id': 'user_123',
}));

// Send message
channel.sink.add(jsonEncode({
  'type': 'message',
  'session_id': sessionId,
  'persona_id': 'support-agent',
  'content': 'I need help with my order',
}));

// Listen for streaming tokens
channel.stream.listen((data) {
  final msg = jsonDecode(data);
  switch (msg['type']) {
    case 'stream_token': print(msg['token']);
    case 'human_escalation': showEscalationDialog(msg['prompt']);
    case 'error': handleError(msg['code'], msg['message']);
  }
});

LLM Model Cascading

Models inherit from Runtime -> Persona -> Sub-agent. Each level can override:

graph TB
    RUNTIME["Runtime Default<br/><b>AgenticSettings.default_model</b><br/><i>e.g., claude-sonnet-4-6</i>"]
    RUNTIME -->|"inherits if<br/>no override"| P1["Persona: support-agent<br/><i>inherits claude-sonnet-4-6</i>"]
    RUNTIME -->|"overrides"| P2["Persona: analyst-agent<br/><b>model_config:</b><br/><i>claude-opus-4-6</i>"]
    RUNTIME -->|"overrides"| P3["Persona: orchestrator<br/><b>model_config:</b><br/><i>gemini-2.5-pro</i>"]

    P2 -->|"inherits"| S1["Sub-agent: data-fetcher<br/><i>inherits claude-opus-4-6</i>"]
    P2 -->|"overrides"| S2["Sub-agent: summarizer<br/><b>model_config:</b><br/><i>claude-haiku-4-5</i><br/><i>(cheaper for summaries)</i>"]

    P3 -->|"overrides"| S3["Sub-agent: researcher<br/><b>model_config:</b><br/><i>claude-opus-4-6</i>"]
    P3 -->|"inherits"| S4["Sub-agent: spec-writer<br/><i>inherits gemini-2.5-pro</i>"]

    style RUNTIME fill:#E74C3C,color:#fff
    style P1 fill:#3498DB,color:#fff
    style P2 fill:#2980B9,color:#fff
    style P3 fill:#2980B9,color:#fff
    style S1 fill:#7FB3D8,color:#fff
    style S2 fill:#1ABC9C,color:#fff
    style S3 fill:#1ABC9C,color:#fff
    style S4 fill:#7FB3D8,color:#fff
Loading

Deployment Modes

graph TB
    subgraph STANDALONE["Standalone Mode"]
        direction TB
        subgraph POD_S["Pod: agentic-core"]
            AC_S["agentic-core<br/>0.0.0.0:8765 (WS)<br/>0.0.0.0:50051 (gRPC)"]
        end
        subgraph POD_B["Pod: backend"]
            NEST_S["NestJS / Serverpod"]
        end
        NEST_S -->|"gRPC (service DNS)"| AC_S
        CLIENT_S["Flutter Client"] -->|"WebSocket (Ingress)"| AC_S
    end

    subgraph SIDECAR["Sidecar Mode"]
        direction TB
        subgraph POD_SC["Pod (shared network namespace)"]
            AC_SC["agentic-core<br/>127.0.0.1:8765 (WS)<br/>127.0.0.1:50051 (gRPC)"]
            NEST_SC["NestJS / Serverpod"]
            NEST_SC -->|"gRPC localhost"| AC_SC
        end
        CLIENT_SC["Flutter Client"] -->|"WebSocket (Ingress)"| AC_SC
    end

    style STANDALONE fill:#3498DB,color:#fff
    style SIDECAR fill:#E67E22,color:#fff
    style POD_SC fill:#D35400,color:#fff
Loading

Set via AGENTIC_MODE=standalone|sidecar. Helm chart supports both.

Observability Stack

graph TB
    subgraph AGENTIC["agentic-core Process"]
        APP["Application Code"]
        OTEL_SDK["OpenTelemetry SDK"]
        STRUCTLOG["structlog (JSON)"]
        PROM_EXP["/metrics endpoint"]
        LANGFUSE_SDK["Langfuse SDK"]
        APP -->|"spans"| OTEL_SDK
        APP -->|"logs with trace_id"| STRUCTLOG
        APP -->|"token counts + cost"| LANGFUSE_SDK
        OTEL_SDK -->|"expose"| PROM_EXP
    end

    subgraph COLLECTOR["OpenTelemetry Collector"]
        RECV["Receivers<br/>OTLP (gRPC/HTTP)"]
        PROC["Processors<br/>batch, tail_sampling"]
        EXP["Exporters"]
    end

    subgraph STORAGE["Observability Backend"]
        PROM["Prometheus<br/><i>Metrics</i>"]
        TEMPO["Grafana Tempo<br/><i>Traces</i>"]
        LOKI["Grafana Loki<br/><i>Logs</i>"]
        AM["Alertmanager"]
        LANGFUSE["Langfuse<br/><i>LLM cost</i>"]
    end

    subgraph VIZ["Visualization"]
        GRAFANA["Grafana<br/>7 pre-built dashboards"]
    end

    OTEL_SDK -->|"OTLP :4317"| RECV
    STRUCTLOG -->|"stdout -> Alloy"| LOKI
    PROM_EXP -->|"scrape"| PROM
    LANGFUSE_SDK --> LANGFUSE
    RECV --> PROC --> EXP
    EXP -->|"traces"| TEMPO
    EXP -->|"metrics"| PROM
    PROM -->|"alerting rules"| AM
    PROM & TEMPO & LOKI --> GRAFANA
    LANGFUSE --> GRAFANA

    style AGENTIC fill:#2ECC71,color:#fff
    style COLLECTOR fill:#3498DB,color:#fff
    style STORAGE fill:#8E44AD,color:#fff
    style VIZ fill:#E67E22,color:#fff
Loading

All signals correlated via trace_id for seamless drill-down: metrics -> traces -> logs -> cost.

Session State Machine

stateDiagram-v2
    [*] --> ACTIVE : CreateSession
    ACTIVE --> PAUSED : explicit pause / connection drop
    ACTIVE --> ESCALATED : HITL node / escalation rule
    ACTIVE --> COMPLETED : graph finished / user ended
    PAUSED --> ACTIVE : resume (within TTL)
    PAUSED --> COMPLETED : TTL expired
    ESCALATED --> ACTIVE : human responded
    COMPLETED --> [*]
Loading

Tool Health & Phantom Tool Prevention

Lesson learned from OpenClaw #50131: tools visible to the LLM but failing at runtime cause hallucinated responses.

stateDiagram-v2
    [*] --> Discovery : MCPBridge.start()
    Discovery --> Healthcheck : tool found
    Healthcheck --> Registered : healthcheck passed
    Healthcheck --> Excluded : healthcheck failed
    Excluded --> [*] : logged as warning, LLM never sees tool

    Registered --> Healthy : serving requests
    Healthy --> Degraded : execution failure / MCP disconnect
    Degraded --> Deregistered : deregister_tool() + ToolDegraded event
    Deregistered --> Healthcheck : MCP server reconnects
    Healthy --> Healthy : successful execution
Loading

Project Status

Phase Status Description
Phase 1: Core + Transport + Runtime In Progress Shared kernel, domain, ports, WebSocket, gRPC, config
Phase 2: Memory + RAG + LangGraph Planned Redis, PG, pgvector, FalkorDB adapters, graph templates, Gemini Embedding
Phase 3: Observability + SRE + Meta-Orchestration Planned OTel, Langfuse, SLO tracking, chaos hooks, GSD, Auto Research
Phase 4: Security + Deployment + Docs Planned Auth, rate limit, PII, Helm, ArgoCD, Terraform, k6 load tests

Full Spec

The complete design specification (1800+ lines, 13 Mermaid diagrams) is at docs/superpowers/specs/2026-03-25-agentic-core-phase1-design.md.

Contributing

Open-source MIT project. See GitHub Issues for current tasks.

git clone https://github.com/lapc506/agentic-core.git
cd agentic-core
python3.12 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest -v  # 67 tests passing

License

MIT

About

Production-ready Python 3.12+ library for AI agent orchestration. Hexagonal Architecture, hybrid transport (WebSocket + gRPC), LangGraph, unified memory, MCP bridge, SRE observability.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages