Skip to content

Repository files navigation

Durable DevOps Agent — Strands + Temporal on Amazon Bedrock AgentCore

NOTE: This is an experimental demo and a work in progress

A simple yet genuinely durable AI agent. A DevOps / on-call agent built with the AWS Strands Agents SDK, made durable with Temporal, reasoning with Anthropic Claude, and deployed on Amazon Bedrock AgentCore as the agent harness (Memory · Gateway · Identity · Observability).

The agent watches a service over HTTP, diagnoses its health with Claude, and can remediate it. Because the agent's reason→act loop runs inside a Temporal workflow, it survives worker crashes, retries flaky calls automatically, and can wait — durably, holding no compute — for a human to approve a disruptive action.

The story in one line: the same Strands agent runs locally, then becomes durable by wrapping it — not rewriting it — with the official temporalio.contrib.strands plugin.


The before / after

Before — a plain Strands agent. Conceptually just an LLM + tools, run once, no durability (a crash mid-remediation loses everything):

agent = Agent(model=AnthropicModel(...), tools=[...], system_prompt=DEVOPS_SYSTEM_PROMPT)
agent("Is the service healthy? Remediate if needed.")

After — the same agent, now durable (durable/workflow.py). The loop runs in a Temporal workflow; the Claude call and each tool call become Temporal activities:

@workflow.defn
class DevOpsAgentWorkflow:
    @workflow.run
    async def run(self, prompt: str) -> str:
        agent = TemporalAgent(                       # model call -> activity
            model="claude",
            start_to_close_timeout=timedelta(seconds=120),
            tools=[activity_as_tool(check_service_health, ...),   # tool call -> activity
                   activity_as_tool(get_service_metrics, ...),
                   self._restart_tool()],            # gated by a durable approval signal
            system_prompt=DEVOPS_SYSTEM_PROMPT,
        )
        return str(await agent.invoke_async(prompt))

The tool logic itself never changes — it lives once in durable/service_ops.py and is wrapped either as a Strands @tool (Phase 1) or a Temporal @activity.defn (Phase 2).


Architecture

        Amazon Bedrock AgentCore (harness): Runtime · Memory · Gateway · Identity · Observability
                                   │ starts / signals
                                   ▼
   Temporal Cloud  ◄────►  Serverless Worker on AWS Lambda  ── runs the Strands agent loop in a
   (durable state)         (temporalio.contrib.strands)         @workflow; Claude call + each tool
                                   │                            call become Temporal activities
                       check_service_health · get_service_metrics · restart_service (HTTP → activities)
                                   │
                              target-service (a self-contained FastAPI app, no external deps)
  • AgentCore = the harness: serverless hosting (Runtime), incident memory (Memory), the service API as MCP tools (Gateway), tool credentials (Identity), traces/metrics (Observability).
  • Temporal = durable execution: the agent loop is a workflow; LLM + tool calls are activities, so they retry independently and the workflow resumes exactly where it left off after any crash.
  • Human-in-the-loop: restart_service waits on a Temporal signal — durably, for as long as needed, consuming no compute.

Layout

Path What
durable/ The whole agent: tool logic (service_ops.py) + prompt (prompts.py) + Temporal workflow, workers (worker_local.py / worker_lambda.py), client, config.
harness/ Amazon Bedrock AgentCore wiring: runtime entrypoint, memory (+ backends), observability.
target-service/ A self-contained FastAPI app the agent monitors (/health, /metrics, /restart, /fault); models api/database/cache components for the status board.
backend/ FastAPI backend for the React UI — streams the live pulse + run timeline over SSE. Includes bridge.py (Temporal client) + service.py (target-service wrappers).
frontend/ React (Vite + TS + Tailwind) "DevOps Mission Control" dashboard (see below) — the only UI.
infra/ Deploy: Temporal Cloud, Lambda/Fargate worker, AgentCore (deploy.md), and Terraform for the real-AWS slice (terraform/: service + CloudWatch + IAM).
tests/ Tool unit tests + an end-to-end durable HITL workflow test (no API key needed).
.mcp.json, .claude/skills/ Dev tooling: MCP servers + authored skills for Strands & AgentCore.

Quickstart (local)

uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"
cp .env.example .env          # set ANTHROPIC_API_KEY (+ CLAUDE_MODEL_ID)

Run the durable agent (needs a Temporal dev server: temporal server start-dev)

python target-service/app.py                                   # terminal 1: the monitored service
python -m durable.worker_local                                 # terminal 2: the durable worker
python -m durable.client start "The service looks down — fix it."   # terminal 3
python -m durable.client approve <workflow-id>                 # approve the restart

Watch it in the Temporal Web UI (http://localhost:8233). The durability demo: start a run, kill the worker (Ctrl-C) mid-flight, restart it — the workflow resumes from history with no duplicated LLM or tool calls.

Port 8080 in use? Run the service on another port and set TARGET_SERVICE_URL accordingly.


Demo UI — DevOps Mission Control (React)

A mission-control dashboard that makes the story legible: the monitored service as a live ECG pulse that goes green→red on fault, an animated durable-activity timeline with the Approve/Deny gate, the AgentCore harness shown live (each pillar with a "how it helps" line lit up by the current run), and an embedded Temporal workflows view. A small FastAPI backend streams the pulse and timeline over SSE via its bridge.py Temporal client. CloudWatch is simulated locally and becomes real with USE_AWS=1 (see Terraform below).

uv pip install -e ".[dev,web]"
cd frontend && npm install && cd ..
bash scripts/dev.sh          # target service + Temporal + worker + backend + frontend
# open http://localhost:5173

Then: Inject fault (pick a component) → Run agent → watch check_service_healthget_service_metricsget_cloudwatch_statusrestart_service stream in and pause at awaiting approvalApprove → service returns to healthy. Kill the worker mid-approval and restart it to prove durability. A 2nd run shows Memory recalling the earlier incident.

Exercise the AgentCore harness locallyscripts/dev.sh also runs the AgentCore Runtime entrypoint (harness/runtime_entrypoint.py, a BedrockAgentCoreApp) on :8081. Tick "route via AgentCore Runtime" in the UI and runs flow through the real Runtime front door → Temporal, on your laptop. Memory is live too via a pluggable backend (MEMORY_BACKEND): a zero-dep local store by default (so the second run on a similar incident shows "recalled N past incidents"), mem0 if you install .[memory], or real AgentCore Memory once AGENTCORE_MEMORY_ID is set.


Deploy (Full AWS + Temporal Cloud)

See infra/deploy.md: provision AgentCore Memory/Gateway/Identity, deploy the worker (Lambda serverless worker, or Fargate fallback), then deploy the Runtime entrypoint and invoke it. The agent loop is identical across local, Fargate, and Lambda.


Tests

python -m pytest        # tool cycle + end-to-end durable human-in-the-loop workflow

The durable test spins up a local Temporal server and a scripted stub model (no Anthropic key) to prove: the agent loop runs in the workflow, the restart tool blocks on the approval signal, and the workflow completes only after approve.


Dev tooling — MCP servers & skills

.mcp.json wires MCP servers for Amazon Bedrock AgentCore, AWS docs, Temporal (ops), Temporal docs, and Strands docs. Two authored skills live in .claude/skills/: strands-agent-builder (build Strands agents + make them durable) and agentcore-harness (wire the AgentCore components). Install the official Temporal developer skill with:

/plugin marketplace add temporalio/agent-skills   # then install "temporal-developer"

About

No description, website, or topics provided.

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages