<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Slash-Commands on Adventures in Claude</title><link>https://adventuresinclaude.ai/tags/slash-commands/</link><description>Recent content in Slash-Commands on Adventures in Claude</description><image><title>Adventures in Claude</title><url>https://adventuresinclaude.ai/og-default.png</url><link>https://adventuresinclaude.ai/og-default.png</link></image><generator>Hugo -- 0.166.0</generator><language>en-us</language><lastBuildDate>Mon, 27 Jul 2026 11:20:11 -0600</lastBuildDate><atom:link href="https://adventuresinclaude.ai/tags/slash-commands/index.xml" rel="self" type="application/rss+xml"/><item><title>Optimizing /start: The Fifteen-Step State Machine</title><link>https://adventuresinclaude.ai/posts/2026-03-15-optimizing-start-the-fifteen-step-state-machine/</link><pubDate>Sun, 15 Mar 2026 20:21:00 -0400</pubDate><guid>https://adventuresinclaude.ai/posts/2026-03-15-optimizing-start-the-fifteen-step-state-machine/</guid><description>How a 1,400-line markdown workflow got faster by doing less defensive work. Parallel fetching, conditional tasks, and inline plans for simple tickets.</description><content:encoded><![CDATA[<table cellpadding="0" cellspacing="0" border="0" width="600" align="center" style="max-width:600px;width:100%;margin:0 auto;"><tr><td><div style="text-align:center;margin-bottom:24px;"><a href="https://adventuresinclaude.ai" style="display:inline-block;"><img src="https://adventuresinclaude.ai/images/email-header.png" alt="Adventures in Claude" width="600" style="max-width:100%;display:block;border:0;" /></a></div><p>The <code>/start</code> command is a 1,400 line markdown state machine with 15 numbered steps that takes a Linear ticket ID and produces a ready-to-test implementation. I type <code>/start AUTM-123</code> and walk away. When I come back, there&rsquo;s a feature branch, an implementation plan posted to Linear, working code, and passing tests.</p>
<p>The <a href="https://adventuresinclaude.ai/posts/2026-03-15-optimizing-commit-for-one-million-tokens/" target="_blank" rel="noopener noreferrer">previous post</a>
 covered optimizing <code>/commit</code> for the 1M context window. This one covers <code>/start</code> - the command that runs <em>before</em> commit, and the one where defensive overhead had the most room to shrink.</p>
<hr>
<h2 id="what-start-actually-does">What /start Actually Does</h2>
<p>The 15 steps, in sequence:</p>
<ol start="0">
<li>Parse arguments, check for existing sessions
0.5. Create 9 workflow tasks with dependency wiring</li>
<li>Detect project type from working directory</li>
<li>Pre-flight validation (clean worktree, valid repo)</li>
<li>Validate ticket ID format</li>
<li>Fetch ticket from Linear</li>
<li>Fetch comments (for reopened ticket detection)</li>
<li>Detect reopened tickets with feedback context</li>
<li>Validate team-repository match, auto-switch if needed
7.1. Load Workflow Profile from CLAUDE.md
7.5. Detect session rules from user message</li>
<li>Create implementation plan (via Plan subagent on Sonnet)</li>
<li>Get user approval on plan</li>
<li>Create feature branch</li>
<li>Update Linear to In Progress, post plan comment</li>
<li>Confirm branch ready</li>
<li>Implement changes (the actual coding)</li>
<li>Run quality gates
14.5. Verification gate</li>
<li>Hand off for user testing</li>
</ol>
<p>Steps 4 through 7.1 were the problem. Five sequential operations, each waiting for the previous one to complete, despite most of them being independent.</p>
<hr>
<h2 id="the-sequential-tax">The Sequential Tax</h2>
<p>I mapped the data dependencies between steps. The question was simple: which operations actually need results from previous operations, and which are just sequential because I wrote them that way?</p>
<p>Step 4 (fetch ticket) returns the UUID and team prefix. Step 5 (fetch comments) needs the UUID. Step 7 (validate team-repo) needs the prefix. Step 7.1 (load profile) needs TARGET_DIR, which Step 7 might change. So there&rsquo;s a real dependency chain: 4 → 5, 4 → 7 → 7.1.</p>
<p>But Step 7.1 (reading CLAUDE.md) doesn&rsquo;t actually need Step 7&rsquo;s <em>result</em> in most cases. Most of the time, you&rsquo;re already in the right repo. The profile read could start immediately - and if Step 7 later discovers a repo mismatch, the profile gets re-read from the correct directory.</p>
<p>This gave me the restructured flow.</p>
<hr>
<h2 id="five-changes">Five Changes</h2>
<h3 id="1-parallel-ticket-fetch--profile-load">1. Parallel Ticket Fetch + Profile Load</h3>
<p><strong>Before:</strong> Five sequential MCP/file calls across Steps 4, 5, and 7.1.</p>
<p><strong>After:</strong> Two parallel messages.</p>
<p>Message 1 dispatches three calls simultaneously:</p>
<ul>
<li><code>get_issue</code> (Linear MCP)</li>
<li><code>Read(CLAUDE.md)</code> (profile load - moved from Step 7.1)</li>
<li>Project detection (already happened in Step 1, but formalizes the parallel structure)</li>
</ul>
<p>Message 2 dispatches two calls that need the UUID from Message 1:</p>
<ul>
<li><code>list_comments</code> (needs UUID)</li>
<li>Team-repo validation (needs prefix)</li>
</ul>
<p>The total wall-clock time drops from about 8 seconds of serial calls to about 3 seconds of two parallel batches. The profile load that previously waited until Step 7.1 now runs concurrently with the ticket fetch. If Step 7 later discovers a repo mismatch (rare), the profile gets re-loaded from the new TARGET_DIR - a small cost paid only in the uncommon case.</p>
<h3 id="2-conditional-task-creation">2. Conditional Task Creation</h3>
<p>Step 0.5 creates 9 tasks with full dependency wiring. That&rsquo;s 2 messages and 17 tool calls. At 200K tokens, this made sense - tasks survive context compaction, so they&rsquo;re the recovery mechanism when Claude loses its place mid-workflow.</p>
<p>At 1M tokens, a single <code>/start</code> workflow rarely compacts. The 9 tasks are overhead for the majority of tickets.</p>
<p>I added conditions. Tasks are created when:</p>
<ul>
<li>Chain mode is active (multiple tickets need per-ticket tracking)</li>
<li>The ticket is an epic child (complex, multi-file work)</li>
<li>Resuming a previous session (tasks already exist)</li>
</ul>
<p>For a simple single-ticket <code>/start</code> - the most common case - task creation is skipped entirely. If the plan turns out to have 5+ implementation tasks, tasks get created retroactively at that point.</p>
<p>The <code>TaskUpdate</code> calls throughout subsequent steps guard against the no-tasks case: <code>if (t1) TaskUpdate(t1.id, ...)</code>. This is a no-op pattern - it adds no overhead when tasks exist, and silently skips when they don&rsquo;t.</p>
<h3 id="3-reduced-checkpoints">3. Reduced Checkpoints</h3>
<p>The old <code>/start</code> wrote session state after Steps 7, 7.5, 8, 9, 10, 11, 12, 13, 14, and 15. That&rsquo;s roughly 10 file writes during a single workflow run. Each write is cheap individually, but collectively they add up - and more importantly, they represent 10 assumptions that context might compact between any two adjacent steps.</p>
<p>With 1M tokens, I reduced to 3 critical checkpoints:</p>
<ol>
<li>After plan approval (Step 9) - the first irreversible decision</li>
<li>After branch creation (Step 10) - git state is now established</li>
<li>At handoff (Step 15) - implementation complete</li>
</ol>
<p>Everything between these points can be reconstructed from git state and the Linear API if context does compact. The plan file is on disk. The branch exists in git. The ticket status is in Linear. The session file doesn&rsquo;t need to track what&rsquo;s already tracked elsewhere.</p>
<h3 id="4-inline-plans-for-simple-tickets">4. Inline Plans for Simple Tickets</h3>
<p>Step 8 always dispatched a Plan subagent on Sonnet. The subagent explores the codebase, reads relevant files, and synthesizes an implementation plan. This keeps verbose search output out of the main context window - a significant concern at 200K tokens, less so at 1M.</p>
<p>For tickets where the description clearly scopes to 1-3 files - &ldquo;fix the button color on the settings page&rdquo; or &ldquo;add a loading spinner to the dashboard&rdquo; - the subagent dispatch overhead (10-15 seconds) isn&rsquo;t justified. The main context has plenty of room for a few file reads and a short plan.</p>
<p>The new logic is conditional:</p>
<ul>
<li>3 or fewer files in scope AND clear description → generate the plan inline using Glob/Grep/Read directly</li>
<li>4+ files, ambiguous description, reopened ticket, epic child → dispatch the Plan subagent as before</li>
</ul>
<p>This trades a small amount of Opus context (the inline plan uses the more expensive model) for 10-15 seconds of wall-clock time on simple tickets. Since simple tickets are the majority, the aggregate savings are meaningful.</p>
<h3 id="5-early-profile-load">5. Early Profile Load</h3>
<p>This isn&rsquo;t a separate optimization - it falls out of Change 1. But it&rsquo;s worth calling out because it changes the step ordering in a way that matters for the rest of the workflow.</p>
<p>The Workflow Profile (base branch, quality gates, review settings, deploy hints) previously loaded at Step 7.1 - after team-repo validation. Now it loads in Message 1 of the parallel fetch, alongside the ticket fetch. The Step 7.1 heading still exists in the command file for documentation purposes, but it notes that execution moved to the parallel fetch.</p>
<p>This means the profile is available earlier. Steps 2-3 (pre-flight validation) still use the basic PROJECT_TYPE from Step 1, but anything from Step 4 onward has full profile access. No behavior change in normal flow - the profile was always available by Step 8 when it was first needed - but the earlier load eliminates a category of bugs where profile fields are referenced before the profile is parsed.</p>
<hr>
<h2 id="what-i-didnt-change">What I Didn&rsquo;t Change</h2>
<p>The session state schema stays the same. All those fields - <code>stashCreated</code>, <code>stashOriginalBranch</code>, <code>chainInvokingDir</code>, <code>ticketContext</code> - are still valuable when context does compact. The schema isn&rsquo;t the problem. Writing it 10 times per workflow was.</p>
<p>The Plan subagent stays for complex tickets. The 1M window is large but not infinite. A thorough codebase exploration for a 10-file feature change produces thousands of lines of Grep and Read output. Keeping that in a subagent&rsquo;s context (on cheaper Sonnet) rather than the main context (on Opus) is still the right trade-off for complex work.</p>
<p>The verification gate at Step 14.5 stays mandatory. This is the one that catches skipped unit tests - a real problem I documented after a production incident. Context compaction making Claude skip tests was the original motivation, and even with 1M tokens reducing compaction frequency, the verification gate costs seconds and prevents hours of debugging.</p>
<hr>
<h2 id="performance-target">Performance Target</h2>
<table>
	<thead>
			<tr>
					<th>Metric</th>
					<th>Before</th>
					<th>After</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Ticket fetch + profile load</td>
					<td>~8s serial</td>
					<td>~3s parallel</td>
			</tr>
			<tr>
					<td>Task creation (simple tickets)</td>
					<td>~4s</td>
					<td>0s (skipped)</td>
			</tr>
			<tr>
					<td>Checkpointing overhead</td>
					<td>~5s (10 writes)</td>
					<td>~2s (3 writes)</td>
			</tr>
			<tr>
					<td>Plan for small tickets</td>
					<td>~25s (subagent)</td>
					<td>~10s (inline)</td>
			</tr>
			<tr>
					<td><strong>Total</strong></td>
					<td>-</td>
					<td><strong>~12-22s saved per /start</strong></td>
			</tr>
	</tbody>
</table>
<p>The range depends on ticket complexity. Simple tickets save the most (inline plan + no tasks = ~22s). Complex tickets save the least (subagent + tasks + full checkpoints = ~12s from the parallel fetch alone).</p>
<hr>
<h2 id="the-pattern">The Pattern</h2>
<p>The same lesson from the <a href="https://adventuresinclaude.ai/posts/2026-03-15-optimizing-commit-for-one-million-tokens/" target="_blank" rel="noopener noreferrer">/commit optimization</a>
 applies here: defensive machinery built for one constraint persists after the constraint changes. The difference with <code>/start</code> is that the machinery is more deeply embedded. Session checkpoints aren&rsquo;t a single function call - they&rsquo;re woven into the control flow between every pair of steps. Removing them required reasoning about what&rsquo;s reconstructable from external state (git, Linear) versus what exists only in the session file.</p>
<p>The next two posts cover <code>/staging</code> and <code>/production</code> - the deployment commands. The pattern shifts there from &ldquo;remove defensive overhead&rdquo; to &ldquo;parallelize independent external checks&rdquo; - Sentry queries, smoke tests, worktree resets. Different shape of optimization, same underlying principle.</p>
</td></tr></table>]]></content:encoded><category>claude-code</category><category>workflow</category><category>optimization</category><category>slash-commands</category><category>context-window</category><category>performance</category></item><item><title>Optimizing /commit for One Million Tokens</title><link>https://adventuresinclaude.ai/posts/2026-03-15-optimizing-commit-for-one-million-tokens/</link><pubDate>Sun, 15 Mar 2026 03:30:00 -0400</pubDate><guid>https://adventuresinclaude.ai/posts/2026-03-15-optimizing-commit-for-one-million-tokens/</guid><description>The 1M context window turned /commit&amp;#39;s bottleneck from context pressure to wall-clock time. Six optimizations cut 55-85 seconds from every commit.</description><content:encoded><![CDATA[<table cellpadding="0" cellspacing="0" border="0" width="600" align="center" style="max-width:600px;width:100%;margin:0 auto;"><tr><td><div style="text-align:center;margin-bottom:24px;"><a href="https://adventuresinclaude.ai" style="display:inline-block;"><img src="https://adventuresinclaude.ai/images/email-header.png" alt="Adventures in Claude" width="600" style="max-width:100%;display:block;border:0;" /></a></div><p><a href="https://adventuresinclaude.ai/posts/2026-03-14-one-million-tokens-and-four-commands-to-rewrite/" target="_blank" rel="noopener noreferrer">Yesterday</a>
 I laid out the case for rewriting my four deployment commands around the 1M token context window. This post covers the first and highest-impact rewrite: <code>/commit</code>.</p>
<p>If you haven&rsquo;t read <a href="https://adventuresinclaude.ai/posts/2026-03-11-exploring-commit-how-my-code-reviews-itself-before-i-push/" target="_blank" rel="noopener noreferrer">the deep dive on how /commit works</a>
, the short version is: it&rsquo;s a 1,170-line markdown state machine that handles quality gates, review triage, agent dispatch, commit message generation, pushing, and Linear updates. One command, twelve steps.</p>
<p>The 1M context window didn&rsquo;t change what <code>/commit</code> does. It changed what <code>/commit</code> needs to <em>defend against</em>. And that defense was expensive.</p>
<hr>
<h2 id="the-audit">The Audit</h2>
<p>I mapped every operation in <code>/commit</code> by type: sequential Bash calls, MCP round-trips, agent dispatches, session file writes. Then I identified which operations were sequential because they had to be (data dependency) versus sequential because they were written that way at 200K tokens when keeping context small mattered more than speed.</p>
<p>The results were clarifying. Three categories of waste:</p>
<ol>
<li><strong>Independent operations running sequentially</strong> — type-check and lint, simplify agents and review agents, Linear read calls</li>
<li><strong>Redundant computation</strong> — the git diff computed three separate times across three steps</li>
<li><strong>Defensive overhead</strong> — ten session file writes during a single commit flow, most of which exist for a compaction scenario that almost never happens at 1M tokens</li>
</ol>
<hr>
<h2 id="six-changes">Six Changes</h2>
<h3 id="1-parallel-quality-gates">1. Parallel Quality Gates</h3>
<p>The simplest win. Step 2 ran <code>pnpm run type-check</code> then <code>pnpm run lint</code> sequentially. Both are read-only operations that don&rsquo;t modify files. They don&rsquo;t depend on each other.</p>
<p><strong>Before:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>pnpm run type-check    <span style="color:#75715e"># ~30s</span>
</span></span><span style="display:flex;"><span>pnpm run lint           <span style="color:#75715e"># ~30s</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Total: ~60s</span>
</span></span></code></pre></div><p><strong>After:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>pnpm turbo type-check lint --concurrency<span style="color:#f92672">=</span><span style="color:#ae81ff">2</span>    <span style="color:#75715e"># ~35s</span>
</span></span></code></pre></div><p>Turbo handles the parallelism natively. Both tasks run simultaneously, bounded by whichever finishes last. The <code>--concurrency=2</code> flag is explicit about what we want — it&rsquo;s not a magic number, it&rsquo;s &ldquo;these two specific tasks, in parallel.&rdquo;</p>
<p><strong>Savings: ~25 seconds per commit.</strong></p>
<h3 id="2-collapsed-simplify--review-pipeline">2. Collapsed Simplify + Review Pipeline</h3>
<p>This was the biggest conceptual change. Previously, <code>/commit</code> had a two-phase pipeline:</p>
<ol>
<li><strong>Phase 1 (Step 2.5):</strong> Dispatch 3 simplify agents on Sonnet. Wait for all to complete. Re-stage any changes they made.</li>
<li><strong>Phase 2 (Step 4):</strong> Dispatch N review agents on Sonnet. Wait for all to complete.</li>
</ol>
<p>The rationale was that review agents should see the &ldquo;improved&rdquo; diff after simplify fixed things. But in practice, simplify finds nothing on the majority of commits. The review agents were waiting 30-45 seconds for a phase that usually produced no changes.</p>
<p><strong>After:</strong> Triage runs first (it needs the file list to determine which agents to dispatch), then ALL agents — simplify and review — launch simultaneously in a single message. In the common case where simplify finds nothing, review agents already see the final diff. If simplify does modify files, only the review agents whose findings overlap with modified files get re-dispatched.</p>
<p>The key insight came from a review comment on the Linear ticket: triage must run before dispatch (you need to know the review level to know which agents to launch), but triage only reads file names — it doesn&rsquo;t need file content. So the sequence is: cache the diff once, run triage on the file list, then dispatch everything in parallel.</p>
<p>This created a new step numbering. The old Step 2.5 (Simplify) and Step 4 (Review Dispatch) merged into Step 2.75 (Parallel Simplify + Review Dispatch). The old Steps 3 and 4 still exist as documentation of the triage logic and agent selection — they just note that execution moved to Step 2.75.</p>
<p><strong>Savings: ~30-45 seconds on commits where simplify finds nothing (majority). ~15-25 seconds when simplify does modify files (targeted re-dispatch instead of full re-run).</strong></p>
<h3 id="3-cached-git-diff">3. Cached Git Diff</h3>
<p>The diff was computed three times:</p>
<ul>
<li>Step 2.5: passed to simplify agents</li>
<li>Step 3: used for triage signal-gathering</li>
<li>Step 4: passed to review agents</li>
</ul>
<p>Now it&rsquo;s computed once in Step 2.5 (&ldquo;Compute and Cache Diff&rdquo;) and the cached <code>DIFF_CONTENT</code> and <code>ALL_FILES</code> variables are reused by all downstream consumers.</p>
<p><strong>Savings: Tokens, not seconds. But fewer tokens means faster processing throughout the pipeline.</strong></p>
<h3 id="4-batched-linear-mcp-calls">4. Batched Linear MCP Calls</h3>
<p>Step 8 (Update Linear) was making 4-6 serial MCP calls: fetch the issue, update status, fetch all workspace labels, update with merged labels, fetch comments (for threading), post progress comment.</p>
<p>A review comment caught my initial design: I&rsquo;d planned 2 messages, but <code>list_comments</code> needs the UUID from <code>get_issue</code>. The corrected design uses 3 messages:</p>
<ol>
<li><code>get_issue</code> (returns UUID)</li>
<li><code>list_issue_labels</code> + <code>list_comments</code> (both need UUID, dispatched in parallel)</li>
<li><code>save_issue</code> (status + labels) + <code>save_comment</code> (dispatched in parallel)</li>
</ol>
<p><strong>Savings: ~5-8 seconds per commit.</strong></p>
<h3 id="5-aggressive-learning-capture-skip">5. Aggressive Learning Capture Skip</h3>
<p>Step 1.5 scans the conversation for learnings to capture before committing. It already skipped in chain mode and short conversations. I added one more skip condition: NONE-level review triage (only docs/config changed). If you&rsquo;re committing a markdown file, there&rsquo;s unlikely to be a novel technical insight worth capturing.</p>
<p><strong>Savings: ~3-5 seconds on doc/config commits.</strong></p>
<h3 id="6-reduced-checkpointing">6. Reduced Checkpointing</h3>
<p>The old <code>/commit</code> wrote session state at multiple points throughout the flow — after quality gates, after triage, after review, after staging. With 200K tokens, this made sense: if context compacted mid-commit, the session file told you where to resume.</p>
<p>With 1M tokens, context compaction during a single <code>/commit</code> run is extremely rare. Two writes are sufficient:</p>
<ol>
<li>Entry: <code>awaiting_user_test</code> → <code>committing</code></li>
<li>Exit: <code>committing</code> → <code>committed</code></li>
</ol>
<p>If context does compact between these two points (unlikely but possible for enormous commits), the session shows <code>committing</code> and you re-run <code>/commit</code> — all steps are idempotent.</p>
<p><strong>Savings: ~2-3 seconds per commit.</strong></p>
<h3 id="bonus-timing-instrumentation">Bonus: Timing Instrumentation</h3>
<p>A review comment on the ticket suggested adding baseline measurements before optimizing. I added <code>COMMIT_START</code> at Step 0 and <code>COMMIT_DURATION</code> at Step 10, displayed in every commit&rsquo;s success summary. This gives us the &ldquo;before&rdquo; numbers to compare against, and — critically — feeds into the pipeline automation system (PLA-781) which uses average commit duration as an advancement criterion.</p>
<hr>
<h2 id="what-i-learned">What I Learned</h2>
<p>The biggest lesson isn&rsquo;t about any specific optimization. It&rsquo;s about how constraints shape architecture in ways that persist long after the constraint changes.</p>
<p>Every one of these sequential patterns had a reason at 200K tokens. Serializing simplify → review kept context smaller. Multiple session checkpoints enabled recovery. Separate diff computations avoided storing large strings in variables. The architecture was <em>correct</em> for its constraint.</p>
<p>When the constraint changed — 200K to 1M, a 5x increase — the architecture didn&rsquo;t automatically adapt. The code still worked. It was just slow. And &ldquo;slow but correct&rdquo; feels fine until you measure it and realize you&rsquo;re spending two minutes on overhead that could take thirty seconds.</p>
<p>The meta-lesson: when a foundational constraint changes by an order of magnitude, audit everything built on that constraint. Don&rsquo;t fix one thing — map the entire dependency chain. I found six optimizations in <code>/commit</code> because I looked at every operation type, not just the one that felt slowest.</p>
<hr>
<h2 id="performance-target">Performance Target</h2>
<table>
	<thead>
			<tr>
					<th>Metric</th>
					<th>Before</th>
					<th>After</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Quality gates</td>
					<td>~60s</td>
					<td>~35s</td>
			</tr>
			<tr>
					<td>Simplify → Review</td>
					<td>~45s serial</td>
					<td>~30s parallel (0s when nothing found)</td>
			</tr>
			<tr>
					<td>Linear updates</td>
					<td>~12s</td>
					<td>~5s</td>
			</tr>
			<tr>
					<td>Learning capture (doc commits)</td>
					<td>~5s</td>
					<td>0s</td>
			</tr>
			<tr>
					<td>Checkpointing</td>
					<td>~5s</td>
					<td>~2s</td>
			</tr>
			<tr>
					<td><strong>Total</strong></td>
					<td><strong>~127s</strong></td>
					<td><strong>~72s</strong></td>
			</tr>
	</tbody>
</table>
<p>I&rsquo;ll update this table with measured numbers after a week of real usage. The timing instrumentation makes that straightforward — every commit logs its duration now.</p>
<hr>
<h2 id="whats-next">What&rsquo;s Next</h2>
<p>Three more commands to optimize: <a href="https://adventuresinclaude.ai/posts/2026-03-14-one-million-tokens-and-four-commands-to-rewrite/" target="_blank" rel="noopener noreferrer"><code>/start</code></a>
 (parallel ticket fetch, conditional task creation, inline plans for simple tickets), <code>/staging</code> (parallel test+build, parallel Sentry queries, parallel worktree resets), and <code>/production</code> (parallel verification, slimmer health audit). Same theme throughout: identify independent operations, run them concurrently, remove defensive overhead that 1M tokens makes unnecessary.</p>
<p>The implementations are done — all four commands are updated. The next three posts will cover what changed and what I learned in each one.</p>
</td></tr></table>]]></content:encoded><category>claude-code</category><category>workflow</category><category>optimization</category><category>slash-commands</category><category>context-window</category><category>performance</category></item><item><title>One Million Tokens and Four Commands to Rewrite</title><link>https://adventuresinclaude.ai/posts/2026-03-14-one-million-tokens-and-four-commands-to-rewrite/</link><pubDate>Sat, 14 Mar 2026 00:25:25 -0400</pubDate><guid>https://adventuresinclaude.ai/posts/2026-03-14-one-million-tokens-and-four-commands-to-rewrite/</guid><description>The 1M token context window changes what&amp;#39;s possible with Claude Code. Four critical workflow commands are getting optimized - here&amp;#39;s what&amp;#39;s coming.</description><content:encoded><![CDATA[<table cellpadding="0" cellspacing="0" border="0" width="600" align="center" style="max-width:600px;width:100%;margin:0 auto;"><tr><td><div style="text-align:center;margin-bottom:24px;"><a href="https://adventuresinclaude.ai" style="display:inline-block;"><img src="https://adventuresinclaude.ai/images/email-header.png" alt="Adventures in Claude" width="600" style="max-width:100%;display:block;border:0;" /></a></div><p>I&rsquo;ve spent the few months building (and endlessly iterating to improve) four markdown state machines - <a href="https://adventuresinclaude.ai/posts/2026-03-10-exploring-start-how-a-markdown-file-runs-my-development-workflow/" target="_blank" rel="noopener noreferrer"><code>/start</code></a>
, <a href="https://adventuresinclaude.ai/posts/2026-03-11-exploring-commit-how-my-code-reviews-itself-before-i-push/" target="_blank" rel="noopener noreferrer"><code>/commit</code></a>
, <code>/staging</code>, and <code>/production</code> - that together manage my development lifecycle. They total about 4,700 lines of structured decision trees. I wrote about the first two already.</p>
<p>Now I&rsquo;m rewriting all four.</p>
<p>The reason is a single number: 1,000,000.</p>
<hr>
<h2 id="the-200k-constraint-shaped-everything">The 200K Constraint Shaped Everything</h2>
<p>The commands didn&rsquo;t start as 4,700 lines of state machines. They started as simple prose instructions - &ldquo;fetch the ticket, create a branch, make a plan.&rdquo; That worked until I hit the 200,000 token context window regularly. Claude would be halfway through implementing a feature and the conversation would compact - Claude Code&rsquo;s way of compressing old messages to make room. After compaction, Claude would lose track of which tasks were done, forget what files it had already modified, or skip steps entirely. I&rsquo;d come back to find it had re-implemented something it already finished, or worse, started writing code without ever getting plan approval.</p>
<p>The state machine structure evolved as a direct response to this. Numbered steps with explicit decision trees replaced prose paragraphs. Disk-based session files captured progress after every step so Claude could recover. Claude Code added features that helped - task lists that survive compaction, for instance - but for long-running workflows like <code>/start</code> that span ticket fetch through implementation through testing, the state machine was still essential. Even with task lists, Claude needed explicit checkpoints and file-based progress tracking to stay on course after compaction. The machinery made the system reliable. It also added a lot of overhead.</p>
<p>This pressure drove almost every architectural decision. Session state files that checkpoint after every single step. Task creation with full dependency wiring so Claude can recover after compaction. Plan subagents that exist partly to keep verbose codebase exploration out of the main context window. Disk-based progress tracking with checkbox files because in-memory state couldn&rsquo;t be trusted to survive.</p>
<p>All of that machinery works. It&rsquo;s also slow.</p>
<hr>
<h2 id="what-changes-with-1m-tokens">What Changes With 1M Tokens</h2>
<p>The 1M context window landed as generally available on Opus 4.6 with no long-context premium. In practical terms, a full <code>/start</code> workflow - command loading, ticket fetch, codebase exploration, plan generation, implementation, and quality gates - can now fit in a single context window without compaction about 85% of the time. The elaborate recovery machinery that made the system reliable at 200K is now overhead for most tickets.</p>
<p>I sat down with Claude and did a systematic analysis of all four commands. I reviewed the commands, the recent blog posts, fetched the Claude Code documentation on context management, and mapped every bottleneck. The shift from &ldquo;context pressure&rdquo; to &ldquo;wall-clock time&rdquo; as the primary constraint reframes every optimization opportunity.</p>
<p>Here&rsquo;s what I found - the highest-impact changes are parallelization:</p>
<ul>
<li>
<p><strong><code>/commit</code></strong>: Quality gates (type-check and lint) run sequentially despite being independent read-only operations. Parallelizing them saves 20-30 seconds on every single commit. The simplify-then-review pipeline serializes two phases that could overlap. Batching Linear MCP calls from 6 serial round-trips to 2 parallel messages saves another 5-10 seconds.</p>
</li>
<li>
<p><strong><code>/start</code></strong>: Ticket fetching, comment loading, and profile reading are three sequential MCP/file operations that could all run in the first parallel message. For simple tickets, nine task creations with dependency wiring add 4 seconds of overhead that&rsquo;s rarely needed with 1M context.</p>
</li>
<li>
<p><strong><code>/staging</code></strong>: Local validation runs tests then builds sequentially - that&rsquo;s 40-60 seconds of unnecessary waiting since they operate on different output directories. Six sequential Sentry queries for post-deploy error checking could be one parallel dispatch.</p>
</li>
<li>
<p><strong><code>/production</code></strong>: Sentry monitoring and smoke tests run back-to-back despite being completely independent. The environment health audit dispatches a full Sonnet subagent when a few curl commands would catch the same critical issues.</p>
</li>
</ul>
<p>Total estimated savings across one full cycle - start a ticket, commit, stage, deploy: about 170 seconds. That&rsquo;s meaningful when the cycle happens dozens of times per day.</p>
<hr>
<h2 id="a-quick-note-about-the-table-of-contents-bug">A Quick Note About the Table of Contents Bug</h2>
<p>If you read the first two posts in this series, you might have noticed the table of contents behaving strangely. I added a sticky sidebar TOC with auto-collapse - when you scrolled past a section, it would collapse to save space. The feature shipped and looked great in testing.</p>
<p>Then it created a scroll trap in Chrome.</p>
<p>The auto-collapse used an IntersectionObserver to watch heading elements. When you scrolled past a heading, the observer fired and collapsed a TOC section. But collapsing a section changed the page height, which shifted the scroll position, which triggered the observer again, which collapsed another section. The page would lock up in a feedback loop - the exact kind of bug that manual testing doesn&rsquo;t catch because it only triggers at specific scroll positions with specific content lengths.</p>
<p>I tried fixing the observer logic twice. The first fix added a debounce. The second fix tracked whether the collapse was user-initiated versus observer-initiated. Both reduced the frequency but didn&rsquo;t eliminate the loop. The third fix was the right one: I removed auto-collapse entirely. The TOC stays expanded. It&rsquo;s less clever and completely reliable.</p>
<p>This is the kind of bug that slips through because the feature worked perfectly in the happy path. I tested it with short posts and long posts, scrolled up and down, clicked TOC links. The feedback loop only appeared with specific combinations of heading density, viewport height, and scroll speed. An automated scroll test or a longer manual session would have caught it - but I was excited about the feature and shipped it fast.</p>
<p>The lesson is one I keep relearning: the clever version of a feature is rarely the right version. A static table of contents does everything users need. The auto-collapse was solving a non-problem.</p>
<hr>
<h2 id="whats-next">What&rsquo;s Next</h2>
<p>Four posts, one per command. Each will cover the analysis, the implementation changes, performance measurements, and what the 1M context window specifically enables. The order follows the dependency chain:</p>
<ol>
<li><code>/commit</code> - the highest-impact optimizations (parallel quality gates, collapsed review pipeline)</li>
<li><code>/start</code> - parallel ticket fetching, reduced checkpointing</li>
<li><code>/staging</code> - parallel test+build, parallel Sentry queries</li>
<li><code>/production</code> - parallel verification, slimmer health audit</li>
</ol>
<p>The theme across all four is the same: the 200K context window made reliability the primary engineering challenge. Elaborate recovery mechanisms, defensive checkpointing, aggressive context delegation to subagents. With 1M tokens, reliability is largely solved by having enough room. The engineering challenge shifts to speed - and speed comes from parallelism.</p>
</td></tr></table>]]></content:encoded><category>claude-code</category><category>workflow</category><category>optimization</category><category>slash-commands</category><category>context-window</category></item><item><title>Exploring /commit: How My Code Reviews Itself Before I Push</title><link>https://adventuresinclaude.ai/posts/2026-03-11-exploring-commit-how-my-code-reviews-itself-before-i-push/</link><pubDate>Wed, 11 Mar 2026 17:29:03 -0700</pubDate><guid>https://adventuresinclaude.ai/posts/2026-03-11-exploring-commit-how-my-code-reviews-itself-before-i-push/</guid><description>Inside /commit - the 1,170-line markdown state machine that triages reviews, dispatches parallel agents, and ships code across twelve repositories</description><content:encoded><![CDATA[<table cellpadding="0" cellspacing="0" border="0" width="600" align="center" style="max-width:600px;width:100%;margin:0 auto;"><tr><td><div style="text-align:center;margin-bottom:24px;"><a href="https://adventuresinclaude.ai" style="display:inline-block;"><img src="https://adventuresinclaude.ai/images/email-header.png" alt="Adventures in Claude" width="600" style="max-width:100%;display:block;border:0;" /></a></div><p>I type <code>/commit</code> after finishing a feature. Claude scans the diff, counts eight changed files across two directories, checks that none of them touch auth or migrations, classifies the review as LIGHT, dispatches a code reviewer and a UI consistency checker in parallel on Sonnet, runs a three-agent simplify pass that catches a redundant API call, generates a commit message referencing the Linear ticket, pushes to origin, posts a threaded progress update under the implementation plan comment, applies an auto-detected <code>frontend</code> label, and sets the status to In Progress.</p>
<p>One command. Twelve steps. A review pipeline that would take me twenty minutes runs in about forty seconds.</p>
<p><code>/commit</code> is 1,170 lines of markdown. Like <a href="/posts/2026-03-10-exploring-start-how-a-markdown-file-runs-my-development-workflow/">/start</a>
, it&rsquo;s not a script - it&rsquo;s a structured decision tree that Claude reads and executes. And like <code>/start</code>, every rule in it exists because something went wrong.</p>
<hr>
<h2 id="the-three-level-review-triage">The Three-Level Review Triage</h2>
<p>The first version of <code>/commit</code> ran a full code review on every commit. Five parallel agents analyzing every diff, even when the only change was a CSS color value. It was thorough and spectacularly wasteful.</p>
<p>The fix was triage. <code>/commit</code> now classifies every commit into one of three levels based on what actually changed:</p>
<pre tabindex="0"><code>NONE  → Only docs, tests, config, CSS. No review agents. Just commit.
LIGHT → Source code changed, under 10 files. Code reviewer + selective agents.
FULL  → 10+ files, shared packages, or sensitive paths. Full agent battery.
</code></pre><p>The classification isn&rsquo;t a guess. Claude runs two bash commands in parallel - one counts files and lines, the other checks every file path against a set of pattern matchers:</p>
<pre tabindex="0"><code>=== Critical Files ===    middleware.ts, auth.ts, /auth/
=== Security Paths ===    payment, billing, webhook
=== Platform Packages === packages/*
=== Migrations ===        supabase/migrations/
</code></pre><p>Any hit on a critical path forces FULL review regardless of file count. A single-line change to <code>middleware.ts</code> gets the same scrutiny as a twenty-file feature.</p>
<p>The rule that matters most is that NONE never applies to source code. Even a one-file <code>.tsx</code> change gets at least LIGHT review. I added this after a &ldquo;small&rdquo; prop rename broke a component in production. The change looked trivial - rename <code>isOpen</code> to <code>isVisible</code> - but the prop was used in three other files that weren&rsquo;t updated. A LIGHT review would have caught the missing references in seconds.</p>
<!-- raw HTML omitted -->
<p>Signals are evaluated in priority order. Path-based overrides win over everything else:</p>
<pre tabindex="0"><code>1. Path-based override? (middleware, auth, migrations, payments, packages)
   → YES → FULL (regardless of file count)

2. All files non-source? (only .md, .css, .test.ts, config)
   → YES → NONE (no agents needed)

3. package.json changed? (NOT exempt - supply chain risk)
   → YES → At least LIGHT

4. File count under 10?
   → YES → LIGHT
   → NO  → FULL

5. Over 200 lines changed?
   → YES → Bump one level up (LIGHT → FULL)
</code></pre><p>After determining the level, content-based signals select which agents run. <code>.tsx</code> files add a UI consistency reviewer. API routes and custom hooks add a silent-failure-hunter. Auth and migration changes add a security auditor at FULL level.</p>
<!-- raw HTML omitted -->
<hr>
<h2 id="agents-that-fix-vs-agents-that-report">Agents That Fix vs Agents That Report</h2>
<p>Before the review agents see the diff, a simplify pass runs. This is three agents dispatched in parallel - a code reuse checker, a code quality checker, and an efficiency checker. They look for different failure modes.</p>
<p>The reuse agent searches the existing codebase for utilities that could replace newly written code. I wrote a custom <code>formatDate()</code> helper in a component and the reuse agent pointed out that <code>@platform/ui</code> already exports one with identical behavior.</p>
<p>The quality agent catches redundant state, copy-paste with slight variation, and parameter sprawl. It found a component that accepted eight props when four of them could be derived from the other four.</p>
<p>The efficiency agent looks for unnecessary work - redundant computations, duplicate API calls, N+1 patterns, and independent operations that run sequentially when they could be parallel. It caught an action that fetched user data, then fetched the same user data again two functions deep.</p>
<p>The key distinction is that simplify agents <em>fix</em> the code. Review agents <em>report</em> on it. The simplify pass edits files directly, re-stages them, and proceeds. The review agents produce findings and a verdict - pass, warn, or fail - that determines whether the commit goes through. I separated these because the review agents were generating reports that said &ldquo;you should extract this utility&rdquo; but never actually doing it. The reports were accurate and completely ignored. Now the fixable stuff gets fixed before review, and the review agents focus on things that require human judgment - architectural decisions, security patterns, spec compliance.</p>
<!-- raw HTML omitted -->
<p>The sequence is deliberate:</p>
<pre tabindex="0"><code>Step 2:   Quality gates (type-check, lint)
Step 2.5: Simplify pass (3 parallel agents → fix issues → re-stage)
Step 3:   Review triage (classify as NONE/LIGHT/FULL)
Step 4:   Review dispatch (parallel agents → findings → verdict)
Step 4.1: Synthesis (merge agent findings → single pass/warn/fail)
Step 6:   Stage and commit
</code></pre><p>Simplify runs before review because it changes the diff. If simplify extracts a utility, the review agents see the cleaner version. If review ran first, its findings would reference code that no longer exists after simplify fixed it.</p>
<p>The synthesis step (4.1) exists because multiple agents can disagree. The code reviewer might say PASS while the silent-failure-hunter says FAIL on a swallowed error. Synthesis produces a single verdict from the combined findings, deduplicates overlapping issues, and applies any review overrides from <code>.claude/review-overrides.json</code> - a file where I can suppress known false positives without editing agent prompts.</p>
<!-- raw HTML omitted -->
<hr>
<h2 id="the-change-relevance-problem">The Change Relevance Problem</h2>
<p>I was on branch <code>feature/INT-28-waitlist-entries</code> building a waitlist feature. Partway through, I noticed some stale Claude command files and cleaned them up. I ran <code>/commit</code>. Claude staged everything - the waitlist code and the unrelated command file cleanup - and committed it all under the INT-28 ticket.</p>
<p>The Linear ticket now had a progress comment about changes to <code>.claude/commands/</code> files that had nothing to do with waitlist entries. The git history for the ticket included commits with unrelated cleanup. It wasn&rsquo;t harmful, but it made the history harder to follow.</p>
<p>Now <code>/commit</code> has a change relevance check at Step 5.75. After extracting the ticket ID from the branch name, it compares the changed files against the ticket&rsquo;s purpose:</p>
<pre tabindex="0"><code>Changes appear related to ticket?
├─ YES → Continue to Step 6
├─ UNCLEAR → Ask user to confirm
└─ NO → Prompt with options
</code></pre><p>Red flags include <code>.claude/</code> changes on an app feature ticket, different app directories than the ticket prefix suggests (an AUTM ticket but only <code>medicaremagic/</code> changes), and config-only changes on an implementation ticket.</p>
<p>When unrelated changes are detected, the prompt gives three options: create a separate branch for the unrelated work, continue on the current branch anyway, or cancel and review what to commit. I almost always pick &ldquo;create a separate branch&rdquo; - it takes five seconds and keeps the git history clean.</p>
<p>There&rsquo;s a complementary check at Step 5.5 - branch/ticket mismatch detection. If the session file says I&rsquo;m working on AUTM-677 but I&rsquo;m on branch <code>feature/INT-28-waitlist-entries</code>, that&rsquo;s almost certainly a mistake. This catches the scenario where I switch worktrees, forget I&rsquo;m in the wrong one, and try to commit. The mismatch prompt saved me from committing IntensityMagic changes to an AuthorMagic ticket at least three times.</p>
<hr>
<h2 id="chain-mode-multi-ticket-commits">Chain Mode: Multi-Ticket Commits</h2>
<p><code>/start-chain INT-366 INT-367 INT-368 INT-369</code> kicks off a chain of related tickets. Claude works through them sequentially - implement, test, commit, advance to the next ticket. The <code>/commit</code> command needs to know when it&rsquo;s inside a chain because the behavior changes in specific ways.</p>
<p>Chain detection happens in Step 0.5. <code>/commit</code> checks for a <code>chain-state.json</code> file and verifies that the current ticket matches the chain&rsquo;s current index:</p>
<pre tabindex="0"><code>chain-state.json exists AND current ticket matches
chain.tickets[chain.currentIndex]?
├─ YES → Set IN_CHAIN = true
│        Display: &#34;Chain mode detected (ticket 2/4)&#34;
└─ NO  → Set IN_CHAIN = false (standard commit)
</code></pre><p>When <code>IN_CHAIN</code> is true, three things change. The batch learning capture (Step 1.5) is skipped because chain commits happen rapidly and capturing after each one is noisy - learnings get captured at the end of the chain instead. The success output is abbreviated - no &ldquo;next steps&rdquo; section, no deploy hints, just the commit SHA and a &ldquo;returning to chain orchestrator&rdquo; message. And the chain-state.json is updated with the commit SHA and status for the completed ticket.</p>
<p>Everything else stays identical. Quality gates run. Simplify runs. Review triage runs at the appropriate level. I was tempted to skip reviews for chain commits because they happen in rapid succession and the context pressure builds - but that&rsquo;s exactly when shortcuts cause problems. A chain of four tickets means four separate feature implementations, and each one deserves the same scrutiny as a standalone commit.</p>
<!-- raw HTML omitted -->
<p>The tricky part is cross-repo chains. If <code>/start-chain</code> was invoked in <code>magic3</code> but one of the tickets routes to <code>~/Code/companyos-intensitymagic</code>, the chain-state.json lives in magic3 while the actual work happens in companyos. The per-ticket session file stores a <code>chainInvokingDir</code> field that points back to magic3:</p>
<pre tabindex="0"><code>Session file has chainInvokingDir set?
├─ YES → CHAIN_STATE_DIR = chainInvokingDir
│        Check: ls &#34;$CHAIN_STATE_DIR/.claude-session/chain-state.json&#34;
└─ NO  → CHAIN_STATE_DIR = (current directory)
         Check: ls .claude-session/chain-state.json
</code></pre><p>One important guardrail: <code>/commit</code> updates the per-ticket entry in chain-state.json (status, commitSha, branch) but does <em>not</em> update the summary counts. The chain orchestrator in <code>/start</code> owns the summary tracking and reads the updated ticket status after <code>/commit</code> returns. If both sides incremented <code>summary.completed</code>, the count would be wrong.</p>
<!-- raw HTML omitted -->
<hr>
<h2 id="one-command-twelve-repositories">One Command, Twelve Repositories</h2>
<p><code>/commit</code> works in every repository I use - Magic Platform, CompanyOS, MagicEA, Freshell, Adventures in Claude, and seven more. Each has different conventions for branching, quality gates, review levels, and deployment. The first version of <code>/commit</code> was written for Magic Platform only. When I tried to use it in CompanyOS, it complained about not being on a feature branch (CompanyOS uses main) and tried to run <code>pnpm run type-check</code> (CompanyOS uses <code>bash scripts/validate.sh</code>).</p>
<p>The fix was the same one <code>/start</code> uses: Workflow Profiles. <code>/commit</code> detects the project from the working directory, reads the profile from that project&rsquo;s CLAUDE.md, and adapts every step. The detection is a simple prefix match:</p>
<pre tabindex="0"><code>Working directory starts with ~/Code/magicea?
  → PROJECT = &#34;magicea&#34;
Working directory starts with ~/Code/content/aic?
  → PROJECT = &#34;adventuresinclaude&#34;
Working directory starts with ~/Code/magic*?
  → PROJECT = &#34;magic-platform&#34;
</code></pre><p>The profile drives everything downstream. Branch protection: <code>direct_to_main</code> is true for Adventures in Claude, so committing on <code>main</code> is allowed. Quality gates: Magic Platform runs type-check and lint, CompanyOS runs a single validation script, Adventures in Claude runs nothing. Review triage: Magic Platform can go up to FULL with five parallel agents, non-platform projects cap at LIGHT with a single code reviewer. Ship method: Magic Platform pushes and defers PR creation to <code>/staging</code>, MagicEA creates a PR immediately, Adventures in Claude just pushes.</p>
<p>Linear integration adapts too. The status update uses <code>profile.ship.linear_status</code> - &ldquo;In Progress&rdquo; for pipeline repos where the commit is a checkpoint, &ldquo;Done&rdquo; for direct-to-main repos where the commit is the final step. The progress comment format changes: pipeline repos say &ldquo;Ready for staging deployment via <code>/staging</code>,&rdquo; direct-to-main repos say &ldquo;Committed to <code>main</code> and pushed.&rdquo;</p>
<!-- raw HTML omitted -->
<p>The final success message is entirely templated from the profile:</p>
<pre tabindex="0"><code>[HEADER - choose one:]
  PR created:        Committed and PR created!
  direct_to_main:    Done -- TICKET-XXX committed and marked Done
  all others:        Work committed for TICKET-XXX

[REVIEW - pipeline repos only:]
  NONE:  Review: Skipped (non-source only)
  LIGHT: Review: LIGHT: code-reviewer PASS, ui-consistency-reviewer PASS
  FULL:  Spec Review: PASS (attempt 1/3)

[CORE - all templates:]
  Branch: feature/INT-391-overlay-cleanup
  Commit: abc1234 - feat: add overlay cleanup

[SHIP - choose one:]
  PR created:        PR: https://github.com/...
  direct_to_main:    Pushed: origin/main
  all others:        Pushed: origin/feature/INT-391-overlay-cleanup

[ALL:]
  Linear: Status -&gt; In Progress, comment added

[NEXT STEPS - most specific match wins:]
  pipeline:      - Deploy to staging: run /staging from magic0
  PR repos:      - Review and merge the PR
  all others:    - [deploy_hint from profile]
</code></pre><p>Adding a new project means writing a Workflow Profile. No changes to <code>/commit</code> itself. The same markdown file runs the same algorithm across twelve repositories, producing twelve different behaviors.</p>
<!-- raw HTML omitted -->
<hr>
<h2 id="auto-labels-and-threaded-comments">Auto-Labels and Threaded Comments</h2>
<p>Two small features in <code>/commit</code> that I use constantly and almost didn&rsquo;t build.</p>
<p>Auto-labeling detects what area of the codebase changed and applies Linear labels. <code>.tsx</code> and <code>.css</code> files get <code>frontend</code>. API routes and services get <code>backend</code>. Migrations get <code>database</code>. The detection runs on path patterns - simple grep checks against the file list. The labels are then merged with existing labels on the ticket, because Linear&rsquo;s <code>save_issue</code> replaces labels rather than appending them. That gotcha cost me an afternoon of debugging silent label drops before I figured out the merge-first pattern.</p>
<p>Threaded comments were added because Linear tickets accumulate noise. Every <code>/start</code> posts an implementation plan comment. Every <code>/commit</code> posts a progress update. If I commit three times during a feature, the ticket has four top-level comments (plan plus three updates) and scanning for the actual discussion becomes tedious.</p>
<p>Now <code>/commit</code> checks for an existing &ldquo;Implementation Plan&rdquo; comment posted by <code>/start</code>. If it finds one, the progress update is posted as a reply threaded under it. The ticket timeline shows one expandable thread for all the automated activity, keeping top-level comments clean for human discussion.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-typescript" data-lang="typescript"><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">planComment</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">comments</span>.<span style="color:#a6e22e">find</span>(
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">c</span> <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">body</span>.<span style="color:#a6e22e">includes</span>(<span style="color:#e6db74">&#34;## Implementation Plan&#34;</span>)
</span></span><span style="display:flex;"><span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">mcp__linear__save_comment</span>({
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">issueId</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;&lt;uuid&gt;&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">body</span>: <span style="color:#66d9ef">progressUpdate</span>,
</span></span><span style="display:flex;"><span>  ...(<span style="color:#a6e22e">planComment</span> <span style="color:#f92672">?</span> { <span style="color:#a6e22e">parentId</span>: <span style="color:#66d9ef">planComment.id</span> } <span style="color:#f92672">:</span> {})
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>Both features are profile-gated. Auto-labeling only runs when <code>profile.labels.auto_detect</code> is true. Threading only happens when a plan comment exists. Neither is visible unless you go looking for it - they just make the project management side of development a little less noisy.</p>
<hr>
<h2 id="the-pattern-separation-of-concerns-in-markdown">The Pattern: Separation of Concerns in Markdown</h2>
<p><code>/start</code> and <code>/commit</code> are two halves of a workflow. <code>/start</code> goes from ticket to implementation - fetch, plan, branch, code. <code>/commit</code> goes from implementation to ship - review, commit, push, update. They share session state through JSON files and share project configuration through Workflow Profiles, but neither knows the other&rsquo;s internal logic.</p>
<p>This separation came from trying to put everything in one file. A 2,500-line <code>/start</code> that also handled committing was unmanageable - not because Claude couldn&rsquo;t read it, but because every change to the review pipeline risked breaking the planning logic. Splitting them made each file independently iterable. I&rsquo;ve rewritten the review triage three times without touching <code>/start</code> at all.</p>
<p>The integration contract is simple. <code>/start</code> creates a session file and a plan file. <code>/commit</code> reads them, updates the session status, and cleans up when done. If <code>/start</code> adds a new field to the session file, <code>/commit</code> ignores it until it has a reason to read it. If <code>/commit</code> adds a new review level, <code>/start</code> doesn&rsquo;t need to know. They communicate through files with stable schemas - the same approach that makes Unix pipes composable.</p>
<p>The markdown-as-state-machine pattern from <a href="/posts/2026-03-10-exploring-start-how-a-markdown-file-runs-my-development-workflow/">yesterday&rsquo;s post</a>
 is the same one at work here. Decision trees, not prose. State on disk, not in memory. Step numbers, not transitions. The only difference is what the machine does - <code>/start</code> orchestrates the beginning of work, <code>/commit</code> orchestrates the end of it.</p>
<hr>
<p>Subscribe via <a href="https://adventuresinclaude.ai/index.xml" target="_blank" rel="noopener noreferrer">RSS</a>
 to follow along. The source is always <a href="https://github.com/bradfeld/adventuresinclaude" target="_blank" rel="noopener noreferrer">on GitHub</a>
.</p>
</td></tr></table>]]></content:encoded><category>claude-code</category><category>workflow</category><category>automation</category><category>slash-commands</category><category>linear</category><category>code-review</category></item><item><title>Exploring /start: How a Markdown File Runs My Development Workflow</title><link>https://adventuresinclaude.ai/posts/2026-03-10-exploring-start-how-a-markdown-file-runs-my-development-workflow/</link><pubDate>Tue, 10 Mar 2026 10:00:00 -0700</pubDate><guid>https://adventuresinclaude.ai/posts/2026-03-10-exploring-start-how-a-markdown-file-runs-my-development-workflow/</guid><description>Inside /start - the 1,400-line markdown state machine that manages my entire development workflow from Linear ticket to deployment</description><content:encoded><![CDATA[<table cellpadding="0" cellspacing="0" border="0" width="600" align="center" style="max-width:600px;width:100%;margin:0 auto;"><tr><td><div style="text-align:center;margin-bottom:24px;"><a href="https://adventuresinclaude.ai" style="display:inline-block;"><img src="https://adventuresinclaude.ai/images/email-header.png" alt="Adventures in Claude" width="600" style="max-width:100%;display:block;border:0;" /></a></div><p>I type <code>/start INT-391</code> and walk away for thirty seconds. When I come back, Claude has fetched the ticket from Linear, read the description and all comments, detected that it belongs to the magic-platform monorepo, checked out a fresh feature branch from <code>preview</code>, explored the codebase to understand what needs to change, generated a detailed implementation plan, posted that plan as a comment on the Linear ticket, set the status to &ldquo;In Progress,&rdquo; and is now waiting for me to approve the plan before it writes any code.</p>
<p>One command. Fifteen steps. Across any of twelve repositories and twelve parallel worktrees.</p>
<p>The <code>/start</code> command is a markdown file. Not a shell script, not a Python program, not a GitHub Action. It&rsquo;s 1,400 lines of structured documentation that Claude Code reads and executes. Every design decision in it came from a real failure.</p>
<hr>
<h2 id="a-markdown-file-is-a-state-machine">A Markdown File Is a State Machine</h2>
<p>The first version of <code>/start</code> was about fifty lines of prose. &ldquo;Fetch the ticket from Linear. Read the description. Create a branch. Explore the codebase and make a plan.&rdquo; It worked - sometimes. Claude would forget to create the branch before starting the plan. It would skip posting the plan to Linear. It would start writing code without waiting for approval. The instructions were clear to a human reader, but Claude treated them as suggestions.</p>
<p>The fix was structure. Not more words - more explicit control flow.</p>
<pre tabindex="0"><code>Session file exists?
├─ YES → Read session file
│        ├─ Steps 0-7 → Restart from Step 1
│        ├─ Step 8+ → Load Workflow Profile first, then resume
│        └─ status = &#34;awaiting_user_test&#34; → Skip to Step 15
└─ NO  → Fresh start, continue with Step 1
</code></pre><p>Decision trees with explicit branching replaced prose paragraphs. Step numbers replaced &ldquo;next, do&hellip;&rdquo; transitions. Checkpoint markers told Claude exactly when to save state. The markdown became less readable to humans and more reliable for Claude.</p>
<p>This is the core insight: a markdown file can be a state machine. Not metaphorically - literally. Each step has a number, preconditions, actions, a decision tree for branching, and a checkpoint that persists state to disk. Claude reads the file, identifies which step it&rsquo;s on, and follows the branches. The structure does the work that an interpreter would do in a traditional programming language.</p>
<!-- raw HTML omitted -->
<pre tabindex="0"><code>Session file exists?
├─ YES → Read session file
│        ├─ Check stored targetDir value
│        │   ├─ If targetDir differs from $PWD:
│        │   │   → Display: &#34;Session found but for different directory&#34;
│        │   │   → Set TARGET_DIR from session&#39;s targetDir
│        │   └─ If targetDir matches $PWD:
│        │       → Set TARGET_DIR = $PWD
│        │
│        ├─ Display: &#34;Found existing session at Step N (status: X)&#34;
│        │
│        └─ Jump to appropriate step based on currentStep:
│            ├─ Steps 0-7 → Restart from Step 1 (no side effects yet)
│            ├─ Step 8+ → Always load Workflow Profile first,
│            │             then resume at stored step
│            └─ status = &#34;awaiting_user_test&#34; → Skip to Step 15
│
└─ NO  → Fresh start, continue with Step 1
</code></pre><p>The key detail: steps 0-7 have no side effects (no branches created, no Linear updates), so they&rsquo;re safe to restart. Steps 8+ have created branches and modified external state, so they must resume exactly where they left off - but only after loading the Workflow Profile, because later steps reference profile fields like <code>base_branch</code> and <code>quality_gates</code>.</p>
<!-- raw HTML omitted -->
<hr>
<h2 id="context-compaction-ate-my-progress">Context Compaction Ate My Progress</h2>
<p>Claude Code compresses old messages as conversations grow long. This is called context compaction, and it&rsquo;s necessary - without it, long coding sessions would hit the context window limit and stop. But compaction means Claude can forget things. Important things. Like which step of a fifteen-step workflow it&rsquo;s on, what the implementation plan says, and which files have already been modified.</p>
<p>The first time I lost an hour of work to compaction, I added session files.</p>
<p>Every <code>/start</code> invocation creates a JSON file on disk: <code>.claude-session/TICKET-XXX.json</code>. It tracks the ticket ID, the current step, the workflow status, the target directory, and whether the user has been asked to test. When context compacts and Claude loses its in-memory state, it re-reads the session file and picks up where it left off.</p>
<p>But the session file only tracks workflow state. The implementation plan is a separate file - <code>.claude-session/TICKET-XXX-plan.md</code> - with checkbox-style tasks:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span><span style="color:#75715e">## Implementation Tasks
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">- [x]</span> Add overlay state to landing page store
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- [x]</span> Create InlineEditableText component
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- [ ]</span> Wire up save action for section headings
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- [ ]</span> Add optimistic update with rollback on error
</span></span></code></pre></div><p>After completing each task, Claude edits the plan file to check the box. When context compacts, Claude re-reads the plan, sees which boxes are checked, and resumes from the first unchecked task. The plan file is the canonical progress tracker - not Claude&rsquo;s memory.</p>
<!-- raw HTML omitted -->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;schemaVersion&#34;</span>: <span style="color:#ae81ff">1</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;ticket&#34;</span>: <span style="color:#e6db74">&#34;INT-391&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;ticketUUID&#34;</span>: <span style="color:#e6db74">&#34;&lt;uuid-from-linear&gt;&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;title&#34;</span>: <span style="color:#e6db74">&#34;Overlay cleanup&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;branch&#34;</span>: <span style="color:#e6db74">&#34;feature/INT-391-overlay-cleanup&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;project&#34;</span>: <span style="color:#e6db74">&#34;magic-platform&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;targetDir&#34;</span>: <span style="color:#e6db74">&#34;/Users/bfeld/Code/magic7&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;stashCreated&#34;</span>: <span style="color:#66d9ef">false</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;createdAt&#34;</span>: <span style="color:#e6db74">&#34;2026-03-10T10:00:00Z&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;updatedAt&#34;</span>: <span style="color:#e6db74">&#34;2026-03-10T10:15:00Z&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;sessionRules&#34;</span>: [],
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;ticketContext&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;description&#34;</span>: <span style="color:#e6db74">&#34;...&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;comments&#34;</span>: [],
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;isReopened&#34;</span>: <span style="color:#66d9ef">false</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;feedbackToAddress&#34;</span>: [],
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;previousImplementation&#34;</span>: <span style="color:#66d9ef">null</span>
</span></span><span style="display:flex;"><span>  },
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;workflow&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;currentStep&#34;</span>: <span style="color:#ae81ff">13</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;status&#34;</span>: <span style="color:#e6db74">&#34;implementing&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;blockedActions&#34;</span>: [],
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;nextAction&#34;</span>: <span style="color:#e6db74">&#34;Continue implementation&#34;</span>
</span></span><span style="display:flex;"><span>  },
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;plan&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;file&#34;</span>: <span style="color:#e6db74">&#34;/Users/bfeld/Code/magic7/.claude-session/INT-391-plan.md&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;postedToLinear&#34;</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>  },
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;progress&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;filesModified&#34;</span>: [<span style="color:#e6db74">&#34;src/app/admin/landing/page.tsx&#34;</span>],
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;testsStatus&#34;</span>: {}
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Every field exists because something went wrong without it. <code>targetDir</code> was added after cross-repo sessions lost track of which directory to work in. <code>stashCreated</code> was added after users forgot they&rsquo;d stashed uncommitted changes before starting a ticket. <code>ticketContext.isReopened</code> was added after Claude kept ignoring feedback comments on reopened tickets.</p>
<!-- raw HTML omitted -->
<hr>
<h2 id="i-kept-starting-tickets-in-the-wrong-repo">I Kept Starting Tickets in the Wrong Repo</h2>
<p>I have twelve repositories. Magic Platform is a monorepo with seven apps. CompanyOS is a standalone repo for business operations. Adventures in Claude is a Hugo blog. MagicEA, Freshell, Overwatch, txvotes, Techstars OS - each lives in its own directory with its own conventions.</p>
<p>The problem: I&rsquo;d type <code>/start COS-87</code> from a Magic Platform worktree and Claude would try to create a feature branch in the wrong repository, explore the wrong codebase, and generate a plan for code that didn&rsquo;t exist there.</p>
<p>The solution is the Team Registry - a YAML block at the top of the <code>/start</code> file that maps every ticket prefix to its repository:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>- <span style="color:#f92672">prefix</span>: [<span style="color:#ae81ff">AUTM, MED, MYH, NEW, PLA, INT, CURE]</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">project_type</span>: <span style="color:#ae81ff">magic-platform</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">directory</span>: <span style="color:#ae81ff">(current worktree)</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">description</span>: <span style="color:#e6db74">&#34;Magic Platform monorepo apps&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>- <span style="color:#f92672">prefix</span>: <span style="color:#ae81ff">COS</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">project_type</span>: <span style="color:#ae81ff">companyos</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">directory</span>: <span style="color:#ae81ff">~/Code/companyos-intensitymagic</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">description</span>: <span style="color:#e6db74">&#34;Company operations&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>- <span style="color:#f92672">prefix</span>: <span style="color:#ae81ff">AIC</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">project_type</span>: <span style="color:#ae81ff">adventuresinclaude</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">directory</span>: <span style="color:#ae81ff">~/Code/content/aic</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">description</span>: <span style="color:#e6db74">&#34;Adventures in Claude blog&#34;</span>
</span></span></code></pre></div><p>When I type <code>/start COS-87</code> from a Magic Platform worktree, the algorithm looks up <code>COS</code> in the registry, finds it maps to <code>companyos</code>, sees that doesn&rsquo;t match the current project type, and switches. All subsequent commands use <code>git -C &quot;$TARGET_DIR&quot;</code> and absolute paths - because Claude can&rsquo;t persist a <code>cd</code> between tool calls. Each Bash invocation starts in the original directory, so the workaround is to never rely on the working directory at all.</p>
<p>The interesting edge case is BAF - Brad&rsquo;s Todos. It&rsquo;s a heterogeneous team in Linear where tickets can route to different repositories depending on what they are. A BAF ticket might be a blog post for feld.com, a feature for CompanyOS, or content for Adventures in Claude. There&rsquo;s no single correct repository, so <code>/start</code> asks:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>- <span style="color:#f92672">prefix</span>: <span style="color:#ae81ff">BAF</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">project_type</span>: <span style="color:#ae81ff">(heterogeneous)</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">routing</span>: <span style="color:#ae81ff">ask_user</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">routing_options</span>:
</span></span><span style="display:flex;"><span>   - <span style="color:#f92672">label</span>: <span style="color:#e6db74">&#34;feld.com blog&#34;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">target_dir</span>: <span style="color:#ae81ff">~/Code/content/feld</span>
</span></span><span style="display:flex;"><span>   - <span style="color:#f92672">label</span>: <span style="color:#e6db74">&#34;Adventures in Claude&#34;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">target_dir</span>: <span style="color:#ae81ff">~/Code/content/aic</span>
</span></span><span style="display:flex;"><span>   - <span style="color:#f92672">label</span>: <span style="color:#e6db74">&#34;CompanyOS&#34;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">target_dir</span>: <span style="color:#ae81ff">~/Code/companyos-intensitymagic</span>
</span></span></code></pre></div><!-- raw HTML omitted -->
<pre tabindex="0"><code>1. Look up the ticket&#39;s team prefix in the Team Registry
2. No matching entry? → Stay in current directory (unknown team)
3. Entry has routing: ask_user? → Show options, let user pick
4. Entry&#39;s project_type matches current? → Stay (already correct)
5. MISMATCH → Set TARGET_DIR from registry entry
   └─ Display: &#34;Ticket COS-87 belongs to team CompanyOS&#34;
      &#34;Target: ~/Code/companyos-intensitymagic&#34;
      &#34;All operations will use absolute paths in the target directory.&#34;
</code></pre><p>After switching, <code>/start</code> runs a post-switch pre-flight: check for uncommitted changes in the target repo, offer to stash them, and verify the repo is in a clean state before proceeding.</p>
<!-- raw HTML omitted -->
<hr>
<h2 id="the-ticket-said-one-thing-reality-said-another">The Ticket Said One Thing, Reality Said Another</h2>
<p>A ticket gets worked on, shipped, and then comes back. I found a bug, an edge case was missed, or the behavior isn&rsquo;t quite right. The ticket gets reopened with feedback in the comments.</p>
<p>Early versions of <code>/start</code> would just read the ticket description and start fresh. The description says &ldquo;add overlay editing to the landing page.&rdquo; Claude reads that, explores the codebase, and generates a plan for adding overlay editing - ignoring the three comments that say &ldquo;the overlay doesn&rsquo;t close when you click outside it&rdquo; and &ldquo;save action fires twice on double-click.&rdquo;</p>
<p>Now <code>/start</code> scans comments for feedback signals:</p>
<pre tabindex="0"><code>A ticket is &#34;reopened&#34; if ANY of these are true:
1. Status is &#34;In Progress&#34; AND comments contain implementation content
2. Comments contain keywords: &#34;sent back&#34;, &#34;bug&#34;, &#34;fix needed&#34;,
   &#34;doesn&#39;t work&#34;, &#34;regression&#34;, &#34;not working&#34;
3. A &#34;Progress Update&#34; comment exists followed by feedback comments
</code></pre><p>When a reopened ticket is detected, <code>/start</code> extracts the specific issues and passes them to the Plan subagent as structured input - not just &ldquo;here&rsquo;s a ticket&rdquo; but &ldquo;here&rsquo;s what was built before and here&rsquo;s what&rsquo;s wrong with it.&rdquo;</p>
<p>The Plan subagent itself is a design choice. It runs on Sonnet (nearly identical SWE-bench scores to Opus at a fraction of the cost) in a separate context window. The subagent explores the codebase - grepping for patterns, reading files, tracing code paths - and all that verbose search output stays in the subagent&rsquo;s context, not the main conversation. The main conversation gets back a clean, structured plan. This matters because codebase exploration can easily consume half the context window, leaving less room for the actual implementation.</p>
<!-- raw HTML omitted -->
<p>The Plan subagent receives a structured prompt with the full ticket context:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span><span style="color:#75715e">## Previous Work &amp; Feedback
</span></span></span><span style="display:flex;"><span>This ticket was previously worked on and sent back.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">### Issues to Address
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> Bug: overlay doesn&#39;t close on outside click
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> Issue: save action fires twice on double-click
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">### Previous Implementation
</span></span></span><span style="display:flex;"><span>Added overlay editing with InlineEditableText component,
</span></span><span style="display:flex;"><span>section heading save action, and optimistic updates.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Focus your implementation on addressing the feedback above.
</span></span></code></pre></div><p>This ensures the Plan subagent searches for the right files - not just the feature files, but the specific code paths that caused issues. Without this context, the subagent would generate a plan for the original ticket, not the reopened one.</p>
<!-- raw HTML omitted -->
<hr>
<h2 id="every-project-is-different">Every Project Is Different</h2>
<p>Magic Platform uses <code>preview</code> as its base branch, requires user testing before commits, runs type-check, lint, and unit tests as quality gates, and ships via pull request. CompanyOS commits via PR to <code>main</code> with a single validation script and no manual testing. Adventures in Claude auto-deploys on push to <code>main</code> with no quality gates at all.</p>
<p>Hardcoding these differences would mean maintaining separate <code>/start</code> commands - or a single command full of <code>if (project === &quot;magic-platform&quot;)</code> branches. Instead, each project declares a Workflow Profile in its CLAUDE.md:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># Magic Platform</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">workflow</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">base_branch</span>: <span style="color:#ae81ff">preview</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">direct_to_main</span>: <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">quality_gates</span>:
</span></span><span style="display:flex;"><span>   - <span style="color:#ae81ff">pnpm run type-check</span>
</span></span><span style="display:flex;"><span>   - <span style="color:#ae81ff">pnpm run lint</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">user_testing</span>: <span style="color:#ae81ff">required</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ship</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">method</span>: <span style="color:#ae81ff">pr</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">target</span>: <span style="color:#ae81ff">preview</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">deploy_hint</span>: <span style="color:#e6db74">&#34;/staging&#34;</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># CompanyOS</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">workflow</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">base_branch</span>: <span style="color:#ae81ff">main</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">direct_to_main</span>: <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">quality_gates</span>: [<span style="color:#e6db74">&#34;bash scripts/validate.sh&#34;</span>]
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">user_testing</span>: <span style="color:#ae81ff">skip</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ship</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">method</span>: <span style="color:#ae81ff">pr</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">target</span>: <span style="color:#ae81ff">main</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">deploy_hint</span>: <span style="color:#e6db74">&#34;PR created - review and merge on GitHub&#34;</span>
</span></span></code></pre></div><p><code>/start</code> reads the Workflow Profile at runtime (Step 7.1) and stores the parsed fields. Every subsequent step references the profile instead of hardcoded values: <code>git checkout -b feature/TICKET origin/[profile.base_branch]</code>, run <code>profile.quality_gates</code> in sequence, set Linear status to <code>profile.ship.linear_status</code> on commit. The command is generic. The profile makes it specific.</p>
<p>Adding a new project means adding one entry to the Team Registry and writing a Workflow Profile in the project&rsquo;s CLAUDE.md. No changes to <code>/start</code> itself.</p>
<hr>
<h2 id="superpowers-the-methodology-plugin">Superpowers: The Methodology Plugin</h2>
<p><code>/start</code> doesn&rsquo;t try to be a complete development methodology. It manages the lifecycle - ticket to deployment. The methodology comes from somewhere else.</p>
<p><a href="https://github.com/obra" target="_blank" rel="noopener noreferrer">Jesse Vincent</a>
 built <a href="https://github.com/obra/superpowers" target="_blank" rel="noopener noreferrer">superpowers</a>
, an open-source plugin that gives coding agents a complete development workflow. The core idea is that your agent shouldn&rsquo;t just jump into writing code - it should brainstorm the design with you first, get your sign-off, write a plan detailed enough for an enthusiastic junior engineer to follow, then execute it with subagents while you watch. Jesse has been iterating on this relentlessly, and the result is one of the most thoughtful pieces of AI tooling I&rsquo;ve seen - not because it&rsquo;s flashy, but because it encodes hard-won lessons about where agents go wrong and how to keep them on track.</p>
<p>Superpowers installs as a single line in settings:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#f92672">&#34;superpowers@superpowers-marketplace&#34;</span>: <span style="color:#66d9ef">true</span> }
</span></span></code></pre></div><p>It auto-updates via the plugin marketplace and provides skills for debugging, verification, brainstorming, plan writing, code review, and TDD. The integration points with <code>/start</code> are specific and deliberate:</p>
<p><strong>Planning (Step 8)</strong>: The Plan subagent follows superpowers&rsquo; plan-writing patterns - required sections (Key Decisions, Rejected Approaches, Edge Cases, Codebase Patterns), task granularity rules (each task is one atomic action), and the principle that a plan must be approved before implementation begins.</p>
<p><strong>Approval (Step 9)</strong>: The &ldquo;present the full plan, get explicit approval, re-present after any revision&rdquo; loop mirrors superpowers&rsquo; brainstorming skill, which requires presenting designs and getting sign-off before touching code.</p>
<p><strong>Verification (Step 14.5)</strong>: This step invokes superpowers&rsquo; <code>verification-before-completion</code> skill. It exists because of a specific failure mode: context compaction would cause Claude to skip quality gates - especially unit tests - and claim &ldquo;done&rdquo; without evidence. The verification skill forces a final check: did all quality gates actually run? Are all plan tasks checked off? It won&rsquo;t let Claude proceed until there&rsquo;s evidence, not just assertions.</p>
<p><strong>The circuit breaker (Step 15)</strong>: After implementation, <code>/start</code> sets the session status to <code>awaiting_user_test</code> and blocks <code>git commit</code>. Even if context compacts and Claude forgets the original instructions, the session file on disk enforces the gate. This is the same principle from <a href="/posts/2026-02-21-running-a-company-on-markdown-files/">the CompanyOS post</a>
 - irreversible actions need explicit approval. Claude can implement, test, and prepare all day long. But the moment a commit needs to leave the working directory, a human says yes.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;workflow&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;status&#34;</span>: <span style="color:#e6db74">&#34;awaiting_user_test&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;blockedActions&#34;</span>: [<span style="color:#e6db74">&#34;git commit&#34;</span>, <span style="color:#e6db74">&#34;git push&#34;</span>],
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;nextAction&#34;</span>: <span style="color:#e6db74">&#34;User tests manually, then runs /commit&#34;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The relationship between <code>/start</code> and superpowers is like a project manager and a methodology framework. <code>/start</code> knows the sequence: fetch ticket, plan, branch, implement, test, hand off. Superpowers knows the standards: how plans should be structured, when verification is required, what counts as evidence. Neither embeds the other&rsquo;s logic. They compose through well-defined integration points - skill invocations and pattern conventions.</p>
<hr>
<h2 id="markdown-as-a-programming-language-for-ai-behavior">Markdown as a Programming Language for AI Behavior</h2>
<p>There&rsquo;s no interpreter executing this markdown. No runtime, no compiler, no AST. Claude reads the file, identifies which step it&rsquo;s on from the session state, and follows the decision trees. The &ldquo;execution engine&rdquo; is Claude&rsquo;s ability to read structured documentation and act on it.</p>
<p>This works because of specific structural choices:</p>
<p><strong>Decision trees, not prose.</strong> &ldquo;If the session file exists and the current step is 8 or higher, load the Workflow Profile first, then resume at the stored step&rdquo; is unambiguous. &ldquo;Resume where you left off&rdquo; is not.</p>
<p><strong>State on disk, not in memory.</strong> Everything that matters - the current step, the plan, task completion status, the target directory - is persisted to files. Claude&rsquo;s memory is unreliable across long sessions. The filesystem is not.</p>
<p><strong>Step numbers, not transitions.</strong> &ldquo;Step 14.5: Verification Gate&rdquo; is a fixed location in the workflow. &ldquo;After testing, verify everything&rdquo; is a suggestion that can be skipped or reinterpreted.</p>
<p><strong>Integration points, not monolithic logic.</strong> <code>/start</code> invokes superpowers skills at specific steps. It reads Workflow Profiles from project CLAUDE.md files. It delegates codebase exploration to a Plan subagent. Each piece does one thing and communicates through structured interfaces - files, JSON schemas, skill invocations.</p>
<p>The broader pattern is this: if you want an AI to do something complex and do it reliably, the answer isn&rsquo;t better prose instructions. It&rsquo;s more structured ones. Decision trees instead of paragraphs. Checkpoints instead of assumptions. State machines encoded in markdown - because that&rsquo;s the format your AI agent already knows how to read.</p>
<hr>
<p>Subscribe via <a href="https://adventuresinclaude.ai/index.xml" target="_blank" rel="noopener noreferrer">RSS</a>
 to follow along. The source is always <a href="https://github.com/bradfeld/adventuresinclaude" target="_blank" rel="noopener noreferrer">on GitHub</a>
.</p>
</td></tr></table>]]></content:encoded><category>claude-code</category><category>workflow</category><category>automation</category><category>slash-commands</category><category>linear</category><category>superpowers</category></item></channel></rss>