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:
/do— interactive task dispatch for anything from “commit these changes” to “fix three bugs and update the docs”/sdlc— a structured 10-step development pipeline with architecture review, TDD, parallel verification, mutation testing, and deployment gates- 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:
- Parse: split into three discrete tasks
- Dependency analysis: the bug fix and docs run in parallel (Wave 1), the commit depends on both (Wave 2)
- Agent matching: bug fix goes to
root-causefor diagnosis thensdlcfor the fix, docs go tosdlc-docs, commit goes tocommit - Present plan: show the wave structure and wait for my approval
- 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:
| Agent | Reviews |
|---|---|
sdlc-architect | Architecture quality (second pass — implementation quality, not fit) |
sdlc-python-test-engineer | Test suite passes, coverage gaps |
sdlc-python-reviewer | Code quality, ruff linting, type hints, DRY |
sdlc-ha-reviewer | HA safety patterns, entity naming, prettier |
sdlc-docs | Documentation-implementation parity |
sdlc-security-reviewer | Secrets 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 Type | What Runs |
|---|---|
| New Python feature | Full pipeline (all 10 steps) |
| Small Python bug fix | Steps 2-5 + 7-9 (skip architecture, mutations) |
| Small HA YAML fix | Steps 3-5 + 7-9 (skip architecture, RED, mutations) |
| Trivial doc-only change | DevOps 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 -psubprocesses — 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
/tmplockfile 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
idleonly dispatch when no normal tasks are pending and the user is asleep (checked via Home Assistant’sinput_boolean.sleepentity) - 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-causeagent first, then route the fix through the SDLC pipeline inheadlessmode (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:
- Searches the vault first for existing context
- Runs 3-4 web searches across different facets of the topic
- Assesses source credibility with a three-tier system (High/Medium/Low-Reject) and requires a minimum of 5 accepted sources
- Fetches and synthesizes accepted sources, surfacing consensus, disagreements, and open questions
- Builds an explanatory framework (define, contextualize, identify mechanisms, distinguish layers, surface the non-obvious)
- Writes a structured Obsidian note to
Research/with frontmatter, key findings, source tables, and revision history - 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
#ClaudeTodoist task like “Research Wazuh agent deployment on HAOS” for overnight research - An
@aicomment like@ai research the alternatives to this toolon any task for contextual research
The Obsidian vault as knowledge base
Everything that isn’t code lives in the Obsidian vault:
| Directory | Contents |
|---|---|
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, commit — sdlc-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-check — validate 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.
- Collect — async collectors pull from Hacker News (Firebase API), Reddit (OAuth), and RSS feeds concurrently
- Filter — a Haiku-tier model does binary relevance filtering in 50-item batches against a personal interest profile
- 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
- Deliver — results are written to the daily Obsidian note as a
## Morning Briefingsection
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:
- Todoist Dispatch picks up a research task overnight, producing a note in
Research/ - I read the research and discuss approach options with Claude interactively
- I write a plan to
Plans/and run/validateto stress-test it /sdlcruns the full pipeline: architecture review, TDD, parallel verification, mutation testing, deployment- The retrospective captures what went well and what to improve
- A follow-up Todoist task drafts a blog post about the feature
- 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.