A snapshot from May 2026. The tended, current-state version lives in the garden: claude-code-workflow.

I run Claude Code on a Proxmox LXC container as my primary development environment. What started as “let me try this AI coding tool” became a multi-agent system that handles everything from quick ad-hoc tasks to full test-driven development lifecycles to unattended overnight work. The whole thing runs headless on a single Linux box, synchronized to my Mac and Home Assistant via Syncthing.

Blog/Posts/My AI-native Home(lab) positions this as the deliberative tier of a 3T architecture — the plane that writes the rules the house runs on. This post is the deep-dive on the workflow itself: three intake paths, a 10-step SDLC pipeline, and the agent pool they share.

Three intake paths, one agent pool

Three ways to get work done:

  1. /do — interactive task dispatch for anything from “commit these changes” to “fix three bugs and update the docs”
  2. /sdlc — a structured 10-step development pipeline with architecture review, TDD, parallel verification, mutation testing, and deployment gates
  3. Todoist Dispatch — a Python cron job that pulls tasks from my Todoist every 15 minutes and routes them to Claude agents autonomously

All three paths share a pool of specialized agents. Each agent is a Markdown file with YAML frontmatter defining its name, description, model, and capabilities. Claude Code reads the description field and auto-delegates based on it — no manual routing table needed.

The agents live in ~/.claude/agents/ on the LXC. The knowledge they reference — style guides, domain documentation, checklists — lives in an Obsidian vault that Syncthing keeps in sync across machines.

Path 1: /do — parse, plan, dispatch

/do is a skill (Claude Code’s equivalent of a slash command) that takes one or more tasks, groups them into dependency waves, and spawns agents to execute them.

When I type /do fix the login bug, update the API docs, commit:

  1. Parse: split into three discrete tasks
  2. Dependency analysis: the bug fix and docs run in parallel (Wave 1), the commit depends on both (Wave 2)
  3. Agent matching: bug fix goes to root-cause for diagnosis then sdlc for the fix, docs go to sdlc-docs, commit goes to commit
  4. Present plan: show the wave structure and wait for my approval
  5. Execute: spawn Wave 1 agents in parallel, wait for completion, then spawn Wave 2

Bug reports get special treatment. If a task describes unexpected behavior, /do creates two subtasks: a diagnosis step using the root-cause agent (which investigates but never fixes), followed by a fix step routed through the SDLC pipeline. The diagnosis runs in an earlier wave so the fix has actual evidence to work from rather than guessing.

For simple single tasks — /do commit, /do research CRISPR — the wave machinery is overkill but the process is the same. One wave, one agent, same discipline.

The constraint that makes this work: the /do orchestrator never does task work itself. Every task goes to a specialized agent. This keeps the orchestrator’s context clean for coordination rather than polluted with implementation details.

Path 2: /sdlc — ten steps, six parallel reviewers

For features, production bugs, or changes that other systems depend on, I use the full SDLC pipeline. This took the most iteration to get right.

Phase 0: think before building

Non-trivial work starts with ideation. The orchestrator does research, discusses approaches with me, writes a design document to the vault’s Plans/ directory, then runs a validate agent to stress-test assumptions before any code is written. The validator asks hard questions: “What happens at the edges? Are there internal contradictions? Will this still work in six months?”

Only after validation does the sdlc-architect agent review the design for architectural fit.

Small changes skip Phase 0 entirely. A one-line config fix doesn’t need a design document.

Phase 1: the TDD pipeline

Ten steps, each owned by a specialist agent:

Step 1 — Architecture Review. The sdlc-architect evaluates whether the proposed change fits existing patterns. No design decision ships without at least two alternatives being evaluated. Verdict options: approve, approve with conditions, request changes, reject.

Step 2 — RED. The sdlc-python-test-engineer writes tests before implementation. These tests define expected behavior and should fail. This is TDD’s red phase, enforced by the pipeline structure rather than developer discipline.

Step 3 — GREEN. The python-engineer (or ha-engineer for Home Assistant YAML) implements code to make the red tests pass. Agent selection is automatic based on what files are changing.

Step 4 — Parallel Verification. Up to six agents run simultaneously in the background:

AgentReviews
sdlc-architectArchitecture quality (second pass — implementation quality, not fit)
sdlc-python-test-engineerTest suite passes, coverage gaps
sdlc-python-reviewerCode quality, ruff linting, type hints, DRY
sdlc-ha-reviewerHA safety patterns, entity naming, prettier
sdlc-docsDocumentation-implementation parity
sdlc-security-reviewerSecrets detection, dependency audit, OWASP patterns

Each agent produces findings independently. Findings are reported to me as each agent completes, not batched at the end.

Step 5 — Fix Every Finding. This is a policy, not a suggestion: every finding gets fixed. No severity tiers. No “this is pre-existing.” No “we’ll address it later.” The only exception is genuine technical tradeoffs where I need to make a judgment call. After fixes, Step 4 runs again. This loops until all agents report clean.

Step 6 — Mutation Testing. The test engineer applies single mutations to the source code — flip a condition, change an operator, remove a function call — runs the test suite, and reverts. If a mutation survives (no test catches the change), that’s a gap. This step runs exclusively: no other agents can touch the code while mutations are being applied and reverted.

Step 7 — DevOps Review. The sdlc-devops agent reads the diff and all agent verdicts, proposes atomic commits with conventional messages, and writes deployment documentation. It reviews but doesn’t execute yet.

Step 8 — Readiness Gate. Every agent must provide active confirmation of what it verified. Not “no objections” but “I verified X and it passes.” Then I do a final code review. DevOps doesn’t execute until I say “go ahead.”

Step 9 — Commit and Deploy. DevOps creates atomic commits, validates Home Assistant config, reloads services in dependency order, and runs post-deploy verification. It never pushes to remote — I manage all git pushes manually.

Step 10 — Retrospective. The sdlc-retro agent reads all previous retrospectives, compares this session against recurring problems, and produces interview questions for me (not the orchestrator). It waits for my answers before applying process improvements. This is how the system gets better over time.

Abbreviated flows

Not every change needs ten steps. The pipeline adapts:

Change TypeWhat Runs
New Python featureFull pipeline (all 10 steps)
Small Python bug fixSteps 2-5 + 7-9 (skip architecture, mutations)
Small HA YAML fixSteps 3-5 + 7-9 (skip architecture, RED, mutations)
Trivial doc-only changeDevOps only (steps 7 + 9)
“Just commit”DevOps only

No agent re-runs another agent’s work

Strict ownership prevents agents from stepping on each other:

  • Tests = sdlc-python-test-engineer (never the code reviewer, never devops)
  • Python linting = sdlc-python-reviewer
  • YAML linting = sdlc-ha-reviewer
  • Commits and reloads = sdlc-devops (never the orchestrator directly)
  • Security = sdlc-security-reviewer (never the code reviewer)

When the Python reviewer finds an issue, it goes back to the Python engineer for fixing. The reviewer doesn’t fix it, and the test engineer doesn’t re-lint.

Deterministic structure, non-deterministic execution

The steps are always the same. The work within each step uses AI judgment. I can trust the process even when the specific decisions vary.

Path 3: Todoist Dispatch — work while I sleep

Todoist is the universal inbox — for AI work and for human-in-the-loop work. A Python cron job runs every 15 minutes on the LXC, triaging every task and routing each one to the right destination. AI tasks and human tasks share the same lane: same triage engine, same retry semantics, same comment thread.

Two-inbox systems fail because the dividing line drifts. A “fix this automation” task starts as a human investigation, becomes an AI diagnosis, becomes an AI fix, becomes a human review. If those phases live in different systems, context is lost at every handoff. Putting everything in Todoist with comment threads as the durable record means the same task carries its full history — root-cause findings, code diffs, deployment confirmation, follow-up questions — without anything being copied between tools.

How tasks get in

Two dispatch sources feed the cron:

Source A — #Claude project tasks. Any open task in my dedicated Claude Todoist project becomes work for an agent. The task title and description become the agent prompt.

Source B — user comments on any task. Any user comment on a Todoist task in any project triggers Claude to process it. The comment text becomes the prompt. Results post back as a reply on the same task.

Alert escalations and other systems feed into these same sources. Household alerts that go unacknowledged for too long create Todoist tasks automatically — the garage door left open all night, the radon level still high after an hour. These land in the #Claude project with the original context attached, so they get scheduled and acted on rather than scrolling out of notification history. Discord alerts can also be promoted to Todoist via a reaction.

When a task appears in both sources, Source B wins because the user comment provides more specific context than the task title alone.

What the Python wrapper handles

The wrapper is pure Python — no AI in scheduling, locking, or error handling:

  • Dispatch via claude -p subprocesses — each task gets its own Claude process with the task content as the prompt. This runs under the existing Claude subscription, so there’s no per-token bill.
  • Single-instance locking via a /tmp lockfile so multiple cron invocations don’t collide
  • Rate limit backoff via a sentinel file — if Claude hits API limits, the wrapper backs off automatically
  • Priority sorting by Todoist priority and due date (overdue first, then due today, then no due date)
  • Idle task scheduling — tasks labeled idle only dispatch when no normal tasks are pending and the user is asleep (checked via Home Assistant’s input_boolean.sleep entity)
  • Failure tracking with retry comments (Failed (attempt 1/3) — <error>) and dead-letter labeling after 3 failures
  • Bot comment verification — after dispatch, the wrapper snapshots comment IDs before and after to verify the agent actually posted results, and reopens tasks that were completed without a response
  • Prompt injection defense — user-provided task content is wrapped in <user-data> tags with those tags stripped from the content itself
  • AI triage — before dispatch, an LLM classifier labels each new task with priority, estimated duration, and a rationale comment. Tasks can be decomposed into subtasks with dependency analysis.
  • Daily summaries appended to the Obsidian daily note with timestamps and task metadata

What Claude handles

Once dispatched, Claude classifies each task as single-step, multi-step, or diagnostic:

  • Single-step: do the work, post a result comment, close the task
  • Multi-step: create Todoist subtasks per step, execute them (parallel or sequential), post results on each, close the parent after all finish
  • Bug reports: spawn the root-cause agent first, then route the fix through the SDLC pipeline in headless mode (no approval gates)

Headless mode matters here. The SDLC pipeline normally waits for my approval at architecture review, readiness gate, and user code review. In headless mode, those gates are skipped — it’s running at 3 AM.

Deterministic wrapper, non-deterministic agent

The Python handles everything that should be predictable — scheduling, concurrency control, error recovery, audit trail. Claude handles everything that requires judgment — understanding the task, choosing an approach, writing code, synthesizing research.

Each component does what it’s best at. The wrapper is fully testable with pytest. Claude’s work is verified by the wrapper’s comment-checking and the SDLC pipeline’s quality gates.

The research agent

The research agent handles deep research on any topic. It:

  1. Searches the vault first for existing context
  2. Runs 3-4 web searches across different facets of the topic
  3. Assesses source credibility with a three-tier system (High/Medium/Low-Reject) and requires a minimum of 5 accepted sources
  4. Fetches and synthesizes accepted sources, surfacing consensus, disagreements, and open questions
  5. Builds an explanatory framework (define, contextualize, identify mechanisms, distinguish layers, surface the non-obvious)
  6. Writes a structured Obsidian note to Research/ with frontmatter, key findings, source tables, and revision history
  7. Inserts backlinks into existing relevant vault notes

Research notes are designed as reference material — scannable with bold key terms, comparison tables, and callouts for caveats. The agent also handles YouTube video analysis: it extracts the transcript, assesses the video’s claims against supplementary sources, and notes where the video oversimplifies or sensationalizes.

When a research note already exists, the agent switches to update mode — it reads the existing note, uses open questions as new search queries, categorizes findings as confirmed/contradicted/updated/new, and progressively refines rather than starting over.

I trigger research through all three intake paths:

  • /do research <topic> for immediate foreground research
  • A #Claude Todoist task like “Research Wazuh agent deployment on HAOS” for overnight research
  • An @ai comment like @ai research the alternatives to this tool on any task for contextual research

The Obsidian vault as knowledge base

Everything that isn’t code lives in the Obsidian vault:

DirectoryContents
Plans/Design documents and implementation plans
Research/Deep research notes with source auditing
Postmortems/Root cause analyses from the root-cause agent
Audits/Security audit and automation discovery reports
Blog/Drafts/Blog post drafts (like this one)
Agents/Reference files that agents read for domain knowledge
Daily Notes/Daily notes with Todoist dispatch summaries

Style guides in the vault define how code, YAML, documentation, and agent definitions should be written. Agents read these guides by absolute path rather than having rules inlined into their definitions — updating a style guide updates all agents at once.

Agent memory — institutional knowledge that persists across sessions — lives in ~/.claude/agent-memory/{agent}/MEMORY.md. The SDLC retro agent, for example, has 17 memory files covering session retrospectives, recurring findings, and platform knowledge. The architect has 12 files covering project-specific design decisions. The cumulative effect is what turns 100 isolated investigations into one ongoing one — root-cause agents reading prior postmortems before opening a new investigation, retro agents recognizing recurring shapes, the architect’s memory updating with patterns learned the hard way.

The agent pool

All three intake paths draw from the same pool of 22 specialized agents, organized by role:

Pipeline orchestration: sdlc — coordinates the 10-step pipeline, spawns subagents per step, and tracks handoff state across phases

Implementation: python-engineer, ha-engineer — they write code, they don’t review it

Review: sdlc-python-reviewer, sdlc-ha-reviewer, sdlc-architect, sdlc-security-reviewer — they review code, they don’t write it

Testing: sdlc-python-test-engineer — owns the entire test stack from RED phase through mutation testing

Operations: sdlc-devops, commitsdlc-devops gates commits and orchestrates deployment within the pipeline; commit handles standalone commits outside the pipeline

Research: research — searches 5+ credible sources, synthesizes findings into Obsidian vault notes

Diagnostics: root-cause — investigates bugs across all domains (Python, HA, infrastructure), queries VictoriaLogs for container logs, traces data flow layer by layer, and writes structured postmortem notes. Diagnoses only; never fixes.

Discovery: automation-discovery — cross-references Home Assistant entity state with vault knowledge to find missing automations, producing a prioritized report

Validation: validate, fact-checkvalidate stress-tests plans, designs, and configs against assumptions, boundary conditions, and internal consistency; fact-check verifies specific claims against sources

Security: security-auditor — periodic security posture assessment across Proxmox, Home Assistant, network infrastructure, and Claude Code configuration

Content: copy-editor — runs multi-pass editorial review (structure, line edit, copy edit, proof) against style guides in the vault. diagram — creates visual arguments as Excalidraw diagrams.

Briefing: morning-briefing-filter, morning-briefing-scorer — the Haiku-tier filter and Sonnet-tier scorer that power the morning briefing pipeline

On-demand health checks (ha-health-check) run as skills rather than standalone agents — they query VictoriaLogs, HA logbook, and automation traces for errors, cross-referencing against the postmortem and plans archive to distinguish current issues from historical ones.

The morning briefing pipeline

The agents produce content, not just code. The morning briefing is a standalone Python project — a cron-triggered pipeline that collects external content, scores it with AI, and delivers curated results to the Obsidian daily note.

  1. Collect — async collectors pull from Hacker News (Firebase API), Reddit (OAuth), and RSS feeds concurrently
  2. Filter — a Haiku-tier model does binary relevance filtering in 50-item batches against a personal interest profile
  3. Score — a Sonnet-tier model assigns 0-10 relevance scores, writes one-liner summaries, and clusters high-scoring items into 2-3 topic themes with synthesis paragraphs
  4. Deliver — results are written to the daily Obsidian note as a ## Morning Briefing section

The pipeline deduplicates via canonical URL hashing and fuzzy title matching (token set ratio >= 85%). It runs through claude -p under the existing subscription — no per-token bill.

At wake-up time, the briefing gets spoken aloud through the house’s TTS system — Gemini TTS to Sonos speakers, targeted to whichever room I’m in via BLE room-presence tracking. Adults and kids get separate briefings; the kids’ version covers school events and weather in age-appropriate language.

How it all connects

A typical feature lifecycle flows through all three paths:

  1. Todoist Dispatch picks up a research task overnight, producing a note in Research/
  2. I read the research and discuss approach options with Claude interactively
  3. I write a plan to Plans/ and run /validate to stress-test it
  4. /sdlc runs the full pipeline: architecture review, TDD, parallel verification, mutation testing, deployment
  5. The retrospective captures what went well and what to improve
  6. A follow-up Todoist task drafts a blog post about the feature
  7. I review the draft, set publish: true, and it deploys via Quartz to Cloudflare Pages

The vault is the connective tissue. Research informs plans. Plans drive implementation. Implementation generates postmortems and retrospectives. Retrospectives feed back into process improvements stored as agent memory.

What I’ve learned

Specialization beats generalization. A general-purpose “do everything” agent produces mediocre results across the board. Specialized agents with strict ownership boundaries produce better work and are easier to debug. The Python reviewer doesn’t touch tests. The test engineer doesn’t touch linting. The devops agent doesn’t re-run reviews.

Deterministic wrappers make AI reliable. The Todoist Dispatch harness doesn’t use AI for scheduling, locking, or retry logic. It uses Python. AI handles the judgment calls within each task. This separation is what makes the system trustworthy enough to run unattended overnight.

“Fix every finding” eliminates an entire category of discussion. No meetings about severity tiers. No debates about “is this really a bug?” If an agent found it, it gets fixed. The only escape hatch is genuine tradeoffs that require human judgment. Sounds extreme until you realize how much time goes to triaging findings instead of fixing them.

The human stays in the loop. No code ships without my review in interactive mode. No architectural decision is final without my approval. The agents propose; I dispose. Headless mode exists for overnight work where I’ve pre-approved the scope, but even then the SDLC quality gates — tests, linting, security — still run.

Agent memory compounds. The retrospective agent comparing session 15 against sessions 1-14 catches patterns no single session would reveal. The architect’s memory of past design decisions prevents the same tradeoff from being re-debated. The system gets better at being a system.

Start with ceremony, then relax it. I started with the full SDLC pipeline for everything and quickly realized that was absurd for a one-line config change. Now I match the ceremony to the risk: /do for quick tasks, /sdlc for anything that touches production systems. The abbreviated flows table is months of calibration.

The infrastructure

The whole system runs on a Proxmox LXC container as the claude user (no sudo). Syncthing synchronizes:

  • The Obsidian vault to my Mac (for Obsidian desktop) and to Home Assistant OS (for addon access)
  • Code repositories for each project
  • Home Assistant YAML packages and addon configurations

Claude Code connects to external systems via MCP (Model Context Protocol) servers: Home Assistant for entity control and automation management, Proxmox for infrastructure queries (read-only), VictoriaLogs for centralized log analysis, Grafana for dashboards and metrics, Todoist for task management within agent sessions, and UniFi for network queries.

A Grafana dashboard tracks the agents themselves — sessions, tool calls, token spend per agent, parallel execution patterns. The observability layer closes the loop: I can see which agents are running, how long they take, and where they spend tokens.

The LXC itself is provisioned by shell scripts in ~/proxmox-tools. No containerization beyond the LXC. No Kubernetes. No cloud services beyond the Todoist and Anthropic APIs. Simple infrastructure, sophisticated orchestration.

What’s next

The system is far from perfect. Context windows get exhausted during long pipeline runs. Agents occasionally produce findings that contradict each other. The retrospective agent keeps flagging the same recurring issues — which means I haven’t fixed the root causes.

But the trajectory is clear: more work at higher quality with less manual effort, while I stay in control of the decisions that matter. Every decision is logged, every finding is reported, every commit is gated on approval. The agents handle execution. I handle direction.