Research plan for CascadiaTech/agentic-workflows: event-driven code agents on GitHub, with Temporal for continuity, LangGraph for agent reasoning, and Lunar for guardrails.
Related: platform-architecture.md · planned-improvements.md · local-dev.md
| Layer | System | Role |
|---|---|---|
| 1 | Kubernetes | Run workers, Jobs, secrets, isolation |
| 2 | Temporal | Durable orchestration — retries, audit, long-running runs |
| 3 | LangGraph | Agent brain — plan → tools → reflect (inside activities) |
| 4 | Lunar | Guardrails on PRs / artifacts — what may merge |
Not interchangeable: Temporal ≠ LangGraph ≠ Lunar. See platform-architecture.md § Agent framework decision.
A GitHub event starts a Temporal workflow that runs a LangGraph agent (tools: git, edit, test, kubectl) in an isolated environment, opens a PR, and Lunar policies decide whether it can merge.
flowchart LR
GH[GitHub event] --> WH[Webhook / Actions trigger]
WH --> TC[Temporal Client]
TC --> WF[RepoAgentWorkflow]
WF --> ACT[Activity: run_langgraph_agent]
subgraph LG[LangGraph]
PLAN[Plan] --> TOOLS[Tools] --> REV[Review]
end
ACT --> LG
TOOLS --> K8s[K8s / workspace]
REV --> PR[Open PR]
PR --> Lunar[Lunar policies]
Lunar --> Gate[PASS / FAIL merge]
| Piece | Status |
|---|---|
kind cluster (kind-training) |
Running |
Postgres + MinIO in lunar namespace |
Deployed |
MinIO S3 buckets (lunar-logs, lunar-resources) |
Pending — fix mc bucket setup; wire hub.s3 in values |
| Lunar chart dry-run | deploy/lunar/values.local.yaml (rendered output gitignored) |
openai-api-key K8s secret |
In lunar namespace (copy to temporal on worker deploy) |
| Temporal workflows | HelloWorkflow, DurabilityDemoWorkflow, AgentRunWorkflow |
| LLM agent activities | plan_task, execute_step (OpenAI in activities) |
| Platform activities | slow_step, list_lunar_pods, write_policy_artifact |
| Generated policy stub | policies/check_dockerfile_user.py (from agent run) |
| Worker on Mac | uv run worker.py → TEMPORAL_ADDRESS default localhost:7233 |
| Worker in Docker/K8s | temporal/Dockerfile, deploy/temporal/ — verified (k8s-worker-test) |
| GitHub remote | CascadiaTech/agentic-workflows — initial commit pending |
| LangGraph agent | Done Phase D1 — repo-agent graph via temporalio.contrib.langgraph |
| GitHub event trigger | Not built |
| Real code agent (clone/edit/PR) | Not built — Phase D2 |
| Lunar Hub enforcing PRs | Blocked on licence |
| Demo | Workflow | Proved |
|---|---|---|
| Hello | HelloWorkflow |
Temporal + worker wiring |
| LLM agent | AgentRunWorkflow |
Plan → execute via OpenAI in activities |
| Durability | DurabilityDemoWorkflow |
15s steps; worker kill + resume (durability-3) |
| K8s probe | AgentRunWorkflow |
kubectl get pods -n lunar from activity |
| Artifact write | AgentRunWorkflow |
Policy stub written to policies/ |
- Stale worker: starting a workflow before restarting the worker after code changes →
Workflow class X is not registered. Fix: one worker, restart after everyworker.pychange, use new workflow ID if prior run failed. - Temporal ≠ infallible: durability is continuity, not guaranteed success. Steps fail; retries and validation are separate concerns.
- Secrets: store API keys in K8s secrets; load into local worker via
kubectl get secret … | base64 -d. Never commit keys (see.gitignore,local/).
Goal: Worker runs in cluster; Temporal server on Mac for dev (host.docker.internal:7233).
- Dockerfile for worker (
temporal/Dockerfile) — Python + kubectl - Deployment + RBAC (
deploy/temporal/) — worker SA can list pods inlunar - Build/deploy scripts (
scripts/build-worker-image.sh,scripts/deploy-temporal-worker.sh) - Deploy worker; verify in-cluster execution (
k8s-worker-testCOMPLETED)
Later: Temporal server in cluster or Temporal Cloud — change TEMPORAL_ADDRESS only.
Goal: Safe public repo; CI validates manifests and Python; no secrets in git.
Remote: https://github.com/CascadiaTech/agentic-workflows
- Git repo created; remote
originconfigured - Initial commit + push to
main -
.github/workflows/ci.yml— Conftest Rego + Temporal import smoke test - Branch protection on
main - GitHub Actions secrets:
OPENAI_API_KEY(only when Actions trigger workflows)
Pick one trigger for v1 (simplest first):
| Option | Pros | Cons |
|---|---|---|
GitHub Actions workflow_dispatch + repository_dispatch |
No public URL; easy on fork | Not true webhook latency |
| Small webhook service on K8s | Real-time; matches Lunar Hub pattern | Needs ingress + GitHub App |
| Temporal Schedules | Good for cron agents | Not event-driven |
Recommended v1: GitHub Action that calls Temporal CLI or a thin Python starter:
-
.github/workflows/start-agent.yml—workflow_dispatch→AgentRunWorkflow - Issue label /
repository_dispatchtriggers (optional)
# Future: .github/workflows/start-agent.yml
on:
issues:
types: [labeled]
workflow_dispatch:
inputs:
goal:
description: Agent goal
required: trueAction job → temporal workflow start --type AgentRunWorkflow ...
Placeholder: services/github-webhook/README.md
Goal: Replace ad-hoc plan_task / execute_step loops with a LangGraph state graph running inside a Temporal activity (or via temporalio.contrib.langgraph).
Why LangGraph: explicit agent state, tool routing, human-in-the-loop interrupts, multi-node agents (planner → coder → reviewer).
Steps:
- Add dependency:
uv add temporalio[langgraph](includeslanggraph) - Create
temporal/state/,nodes/,graph/,config/— graph + centralized prompts - Evolve
AgentRunWorkflowto invoke graph viaLangGraphPlugin - Keep Temporal workflow deterministic; LLM in graph nodes (
execute_in: activity)
Reference: Temporal LangGraph plugin docs · local skill .cursor/skills/temporal-developer/references/python/integrations/langgraph.md
Migrate from: temporal/activities/agent.py (manual OpenAI calls)
- M1: sqlite-vec + committed seed chunks + Ollama/OpenAI embedders
- M1: Baseline
memory/baseline/ollama-nomic.sqlitefor clone-and-go (768-dim, nomic-embed-text:v1.5) - M1: Graph nodes
retrieve_context,write_observation - M1: Double-plan —
draft_plan→ retrieve →refine_plan; skipexecutefor doc goals - Repair sweep:
RepairSweepWorkflow+local/agent-runs/log stream — see agent-run-logs.md - M2 scaffold: pgvector on Postgres (
pgvector/pgvector:pg16,deploy/postgres/pgvector-init.yaml) - M3: Neo4j graph RAG (optional — only if entity-relationship queries needed)
See memory/README.md.
- S1: Vendored MIT skill content — agent-skills.md,
third_party/, Cursor rules - S1: Temporal prompt injection —
AGENT_PONYTAIL,AGENT_CAVEMANintemporal/config/agent_skills.py - S2: Role-specific graphs (planner=caveman, builder=ponytail) in multi-agent mission workflow
- S3: Optional Caveman Proxy for worker input compression (upstream BSL CLI, not vendored)
See multi-agent.md for graph engineering target (delegator DAG, fan-in, shared memory).
- F1:
MissionWorkflow+ Postgres board + parallel child workflows - F2: Scope document,
depends_onexecution,task_outputs, LLM fan-in - F3: Role graphs — doc-agent, review-agent
- F4: K8s worker always-on (deferred during local iteration)
Done (local lite): LangGraph nodes propose_edits → apply_edits write files in this repo via path allowlist (temporal/config/agent_config.py). No git clone/PR yet.
Extend LangGraph tools / activities to:
- Clone target repo (
GITHUB_TOKENfrom K8s secret) - Edit files in workspace — this repo, allowlisted paths, max 3 files/run
- Run tests / lint in activity (e.g.
./scripts/ci-check.sh) - Open PR via
ghCLI or GitHub API - Return PR URL to Temporal workflow
Secrets needed: GITHUB_TOKEN or GitHub App credentials (separate from OpenAI).
Execution environment: worker pod with repo checkout, or ephemeral K8s Job per run (decide after D1).
- Lunar Hub live (licence)
- CI Tracer on this repo
- Policy: generated PRs must pass tests, non-root Dockerfile, no secrets in diff
- Workflow waits for Lunar check status (poll activity or webhook signal)
Connect generated policies/check_dockerfile_user.py to real Lunar Python SDK when licence available. Until then: guardrails-alternatives.md (Conftest + Guardrails AI).
Goal: Same gate pattern without Hub — portfolio stays shippable.
- G1: Conftest Rego — Dockerfile non-root in CI
- G2: Guardrails AI on LangGraph outputs (plan JSON, PR body)
- G3: Kyverno — agent Jobs require limits + non-root
See guardrails-alternatives.md.
Kubernetes/
├── deploy/
│ ├── lunar/ # Helm values, chart-defaults (rendered.yaml gitignored)
│ ├── postgres/ # Postgres manifest
│ ├── minio/ # MinIO manifest (path may still say deploy/postgres/ — tidy later)
│ └── temporal/ # Worker Deployment + RBAC
├── temporal/ # Workflows, activities, Dockerfile, worker.py
│ └── agents/ # Phase D1: LangGraph graphs + tools (planned)
├── services/
│ └── github-webhook/ # Phase C placeholder
├── policies/ # Agent-generated + future Lunar policies
├── scripts/ # build-worker-image, deploy-temporal-worker
├── docs/ # Plans + session logs
└── README.md
Still to add: config/lunar-config.yml, collectors/, .github/workflows/ci.yml, ingress.
- Workflows deterministic — LangGraph + LLM + git + kubectl in activities only
- Secrets in K8s — never in git; GitHub Actions secrets for CI-only keys
- One worker per task queue in dev — avoid stale code polling
- Lunar governs output — Temporal governs process; LangGraph governs agent loop; don't conflate them
- Idempotent activities — same workflow ID + dedupe keys where possible
- LangGraph inside Temporal — not LangGraph instead of Temporal
- Agent framework → LangGraph inside Temporal activities
- Worker namespace layout →
temporalnamespace;lunarfor infra - Git remote → CascadiaTech/agentic-workflows
- Temporal Cloud vs self-hosted server in kind? → Dev: Mac
start-dev; prod TBD - GitHub App vs PAT for agent git access?
- LangGraph: Temporal plugin vs single
run_langgraph_agentactivity wrapping graph? - v1 event trigger: GitHub Actions vs webhook service?
| Date | Change |
|---|---|
| 2026-08-18 | Initial roadmap; K8s worker deploy scaffold |
| 2026-08-18 | Demos completed (LLM, durability, kubectl, artifact); lessons + status table |
| 2026-08-19 | LangGraph as agent layer (Phase D1/D2); four-layer architecture; git remote; K8s worker verified |