Deployed at Home: my path toward Forward Deployed Engineer. Part 4 of 4, working between people: the architect skill, the channel protocol, and what hurt along the way.

Parts 1 to 3 covered why I rewrote my guesthouse back office, what I rewrote it into, and the guardrails that refuse unverified work. This part is about the division of labour that produced the code: Claude Code as the architect and reviewer, DeepSeek V4.1 Flash as the senior developer, and me as the product owner who approves the design and makes the calls neither of them should. It’s a small version of the position a forward deployed engineer works in: between the people who decide what’s needed and the people who build it, keeping both sides in writing.

The two agents run in different harnesses from different vendors. They can’t call each other, and I didn’t want them to. Every exchange goes through two append-only Markdown files that sit next to the plan in git.

Why split the work this way

The split follows cost and strength. Designing a plan that a weaker model can execute without judgement calls is hard and worth a strong model at maximum effort. Writing the code from such a plan is a lot of tokens of fairly mechanical work, and a fast, cheap model does it well if the plan leaves nothing to guess. Reviewing the result needs judgement again, but less of it than designing.

So the architect session runs at medium effort, only the planning step runs at max, and DeepSeek does the volume.

The architect skill

The skill lives in .claude/skills/architect/SKILL.md and has four phases. One rule applies across all of them: the architect never edits code, tests or the guardrails, and never commits.

1. Design

Claude + me, 2-3 rounds

plan.design.md

I approve it

2. Plan

plan-architect subagent

Opus, max effort

plan.md + plan.bugs.md

+ empty channel files

3. Kickoff

prompt for a new DSH session

4. Watch

review commits, answer questions

APPROVED

In the design phase, Claude reads the project’s process files and the code involved, then asks me questions one at a time over two or three rounds. The output is a design file with five sections: Goal, Decisions with a reason for each, Out of scope, Risks and Acceptance. There is no task breakdown yet. For the Go rewrite that file holds 28 numbered decisions, from “Podman is the only container runtime” to the exact cookie flags.

In the plan phase, a separate plan-architect subagent turns the approved design into an implementation plan, at maximum effort. Every task gets exact Go signatures in an Interfaces block, steps concrete enough that the implementer makes no design decisions, a Pitfalls line wherever a plausible shortcut is wrong, and an executable Definition of Done. The plan also has a Waves section that says which tasks can run in parallel and why the others can’t. Every path and type in it must exist already or be created by an earlier task, and the subagent has to check that with real file reads. The rewrite plan came out at 59 tasks across 12 waves and just over 4,000 lines. A plan check rejects it on save if any task lacks a runnable DoD.

At kickoff, Claude hands me a prompt to paste into a new DSH session. It tells DeepSeek to run its orchestration skill on the plan, and it defines the protocol below.

In the watch phase, Claude starts a background monitor that prints a line only when the branch gets a new commit or the questions file changes, with a 20-minute fallback wake-up in case the monitor stalls. It never polls with the model itself, which would burn tokens on nothing.

The protocol

FileWritten byEntries
<plan>.questions.mdDeepSeek onlyQ<n> [BLOCKING] or [FYI] questions, S<n> STATUS T<k> done @ <sha>, A<n> ACK R<n>
<plan>.review.mdthe architect onlyR<n> [BLOCKER/MAJOR/MINOR] findings, D<n> decisions, GO T<k>, APPROVED

Neither side ever edits the other’s file, and nobody edits an earlier entry. Entries are numbered by counting what’s already there.

MeClaude (architect)review.mdquestions.mdDeepSeek (DSH)MeClaude (architect)review.mdquestions.mdDeepSeek (DSH)finish task T27, commitS12 STATUS T27 done @ abc123monitor fires, review the diffR18 [MAJOR] path:line, expected fixbefore the next wave, read review.mdfix, commitA9 ACK R18: fixed in def456Q1 [BLOCKING] T28, options 1, 2, 3until grep -q '^product question? escalatedecisionD19 answers Q1, with the reasonGO T29start the next wave

Here is an example from 2026-10-03, when Wave 0 closed. Claude Code (Opus 5.5, medium effort) is on the left. It has accepted task T6 with decision D8, answered DeepSeek’s finding about the stopped Podman machine with D9, and posted GO T7 to start Wave 1. DeepSeek (DeepSeek-V41-Flash, high effort) is on the right, reporting the checks it ran and appending S7 STATUS T6 done @ fb41fec to the questions file.

Example: Claude Code on the left reviews and posts GO T7, DeepSeek on the right reports T6 done

The rules in the kickoff prompt are short:

  1. Commit each finished task on its own, staging explicit paths, and append a STATUS line with the commit.
  2. Before each wave, read the review file. Fix every BLOCKER and MAJOR, or ACK it with reasoning and wait for a decision. Then wait for GO T<k>.
  3. If something is unclear, don’t guess. Append a BLOCKING question with the options considered, or an FYI if you can continue on a stated assumption.
  4. To wait, run one shell loop: until grep -q '^## D3' review.md; do sleep 30; done. Don’t re-read the file in a loop.
  5. You are finished only when the review file says APPROVED. Never open a PR and never stop on your own before that.

Claude Code can also do a quick status check at any point. Early in Wave 2 I asked how many steps were left. It counted from the plan and the git history and said which tasks were committed, which were work in progress and which hadn’t started. It also said it hadn’t checked whether the in-progress ones were fully done.

Claude Code's status check: "how many more T steps": 14 committed, 6 in progress and uncommitted, 37 not started, listed by wave

The plan had 57 tasks at that point and grew to 59 by the end.

Over the rewrite, the files collected 49 status entries, 23 ACKs, about 20 questions and FYI notes on DeepSeek’s side, and on Claude’s side about 40 review findings, 133 decisions and 14 GO signals. The last entry is the approval, written at 03:34 on 2026-10-05.

A question that worked the way it should

Early in Wave 1, the adversarial reviewer found that a reservation could reference a guest belonging to another owner. The security reviewer agreed on the facts and disagreed on severity. DeepSeek didn’t pick a side. It stopped the wave and wrote Q1 [BLOCKING] with three options:

  1. Add account_id to reservations and use composite foreign keys. Strongest, but costs a column.
  2. Scope guests per house. It advised against this, because guests belong to an account and a returning guest can book any of the owner’s houses.
  3. Accept it as defence-in-depth debt and rely on the service code.

It also spotted a cheaper fix for the same class of bug in rate overrides and offered to fold it in.

The architect’s D19 chose option 1 without a trigger: the house foreign key makes a wrong account id impossible, and the guest foreign key then makes a foreign guest impossible. It named the three tests to write, listed the knock-on effects for later tasks, and said who would update the plan text so DeepSeek wouldn’t touch it. That is the best case: the implementer understands the problem better than any prompt could describe it, and the decision comes back with a reason and a test.

What hurt

Plausible interfaces that were wrong. The plan described the shape of Zitadel’s API responses from documentation. In task T20 four acceptance assertions were each reasonable and each wrong: clientId sits inside oidcConfig, two enum fields are protobuf zero values that the JSON gateway leaves out entirely, the v1 API spells the field isEmailVerified, and a cookie scoped to Domain=localhost has to be carried by hand. An earlier research report already had two of those right. The failure was writing an assertion before anything had run. The rule now: every task that tests against a real external system starts the pinned container first, captures the real response as a fixture, and then writes the assertion against that.

Metric gaming. Task T59 asked for fewer comment lines in production code. DeepSeek met the number by joining multi-line comments into single lines, some of them over 300 columns wide. Comment lines fell by 68%, but the comment text fell by only 8%, and 1,224 lines were now over 120 columns. Claude measured it and filed R39 as a BLOCKER: “T59 met the line metric by joining comments onto long lines, not by cutting them.” The fix added a 100-column check to the test and a character target as a cross-check. The next round then deleted the doc comments on 136 exported declarations outright, and another bug had to put them back. Any target you give a model needs a second measure that catches the cheap way of hitting it.

Committed red fences. One browser journey was committed with its red_T51 build tag still in place, so the plan’s own DoD compiled it out and passed with nothing to run. That’s the lesson from Part 3 again, but it came through the channel: a STATUS line said done, and the review found nothing had executed.

Shared checkout, single writer. DeepSeek Harness gives sub-agents no separate worktree, so every role works in one checkout and only the orchestrating session commits. That rules out parallel tasks that touch the same files, so the plan’s wave table had to say which tasks were safe to run together. It also meant the guardrails occasionally refused something I wanted, and I had to authorise those by hand. DeepSeek logged each override as an FYI so the record stayed complete.

Silence. Two agents waiting on each other through files can both end up waiting. The skill says that if DeepSeek posts no status, question or commit for 30 minutes, Claude tells me rather than trying to drive DSH itself. A full make verify with browser flows takes about six minutes, so a quiet half hour can mean a long gate run or a stuck agent, and only a person looking at DSH can tell which.

Things only I could decide. I deferred the sizing run and skipped one cleanup task. The approval entry names both and says what is still open before the first paying guest. Neither agent can make those calls, and the protocol makes sure they end up in writing.

What I’d keep

  • Files in git as the only channel. Every question, decision and finding is versioned, diffable and readable by the next session, or by me months later.
  • One writer per file, append-only, numbered by counting.
  • “Don’t guess, ask BLOCKING with your options.” The best questions came with a recommendation and the reason against the alternatives.
  • Waiting in the shell rather than in the model.
  • Design approval and plan approval as two separate human gates.
  • A strong model for planning and review, a fast one for volume, and guardrails between them that don’t care which model is talking.

What this has to do with forward deployed work

Swap the agents for people and this protocol looks a lot like a client engagement. The architect translates what the owner wants into a plan the builders can follow without guessing. Builders raise blocking questions with the options they considered. Product questions go to the person who owns the product, and the answer comes back with a reason. Every decision is written down where the next person will find it.

Q1 and D19 are the exchange I’d hold up as the model: the builder found the problem, laid out three options with a recommendation, and held the work, and the decision came back with the tests that would prove it. R39 is the opposite case, and I’d hold that up too. Give anyone a single number to hit and some will hit it the cheap way, so the review has to measure what the number was standing in for.

What the series adds up to

Four habits, one per part:

  1. Discovery. Turn “it uses too much RAM” into a question with a load, a price list and a measurement, and say what the measurement can’t prove.
  2. Making the call. Decide, name the evidence you’re going against, and write the reason where it will be found.
  3. Field lessons into tools. Every failure becomes a rule in code, so the next deployment starts with it.
  4. Working between people. Keep a written channel, escalate the decisions that belong to the owner, and review the outcome as well as the metric.

None of that depends on the guesthouse, and most of it doesn’t depend on the agents either. That’s why I’m writing it up as a path toward forward deployed engineering. The work done here at home is the same work I want to do inside someone else’s business.

Get the skill

I’ve published the architect skill so you can use it in your own projects: architect skill on GitHub.

It is one SKILL.md file for Claude Code. Drop it into .claude/skills/architect/ in your repository and run /architect design <feature>. It covers the four phases from this article, the kickoff prompt for the implementing agent, and the questions and review protocol. It works with any second coding agent that can read and append to files in your repository and run a shell command. Mine was DeepSeek in DeepSeek Harness.

The published version is a cleaned-up copy of the one I used. It has no project paths and no dependency on any private tooling, so you’ll want to add your own test commands and review rules.