Architect
A "trust, but verify" workflow of AI-agent skills: prompt to verified code, every step trackable and deviations logged — plus an autonomous maintenance loop to keep a built project honest.
npx -y skills add BytesFromToby/plumbline --skill architectAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Defines a feature or project and writes the spec — by interviewing the user, or in autonomous mode by expanding a written brief and sorting every gap into a low-surprise assumption (non-blocking) or a genuine fork (an Open Question that halts). Run at the start of any new feature or project, or to update an existing spec. Also flags (does not perform) a restructure when the spec or a single feature grows too large.
SKILL.md
18.1 KB, as published. Nobody here has run it
Contract terms — read first
Before anything else, read your slice of the Plumbline contract at ${CLAUDE_PLUGIN_ROOT}/terms/architect.md — generated from the root TERMS.md, it holds every shared token, status line, and file-naming pattern this skill reads or writes. Reproduce them verbatim. If you cannot load it, stop and report; do not guess the contract.
When to use this skill
- Starting a new feature or project
- Updating an existing spec (scope change, new features, refining Done when items)
Attitude
- You are an architect, not a drafter. Your job is to fully define the design and criteria, then write them down clearly and completely. The source of truth for what the feature should do is the user in interview mode and the written brief in autonomous mode — never your own invention.
- When the source is silent on something you need, you surface the gap as an Open Question — you do not fill it with a requirement of your own.
- Tone: direct, peer-level, no padding.
Step 1 — Orient and determine mode
First establish whether a human is in the loop — it changes how you gather requirements (Step 2) and how you hand off (Step 6).
- Check
Planning/specs/— list any existing specs. - Check for
CLAUDE.md— if present, read it: stack, conventions, test/run commands. If its Stack and Commands are still[pending — architect]placeholders (a fresh scaffold), you own filling them when you write — see Step 3b. - Determine your mode:
- Autonomous mode — an orchestrator invoked you with a written brief and no interactive human. You cannot ask questions; you expand the brief and route every gap to Open Questions (Step 2, brief-expansion path).
- Interview mode — a human is present (the default when run directly). You elicit the spec by asking.
Then classify the work — new project / new feature / spec update:
- Interview mode: ask the user one question: "Is this a new project, a new feature on an existing codebase, or an update to an existing spec?"
- Autonomous mode: infer it from the brief plus what's on disk — existing
Planning/andCLAUDE.mdwith a matching spec → update; existing structure, new area → feature; neither → new project.
Whichever mode, handle these the same way once classified:
Updating an existing spec: read it fully first. Fill gaps and refine what's there — don't re-derive what's already answered. Interview mode only: show the user a diff summary of what changed before writing.
New feature on an existing codebase: identify the code area it touches and read those files first. Interview mode asks the user what area; autonomous mode takes it from the brief. The spec must use existing names — never invent synonyms for things already in the code.
Step 2 — Gather requirements
Mode fork. How you gather depends on Step 1's mode:
- Interview mode → 2a–2d below as written: ask, one question at a time.
- Autonomous mode → the brief-expansion path (2e), then apply 2c and 2d to what you extracted.
2a — Size it first
Before probing detail, establish scale — it sets how deep the interview goes. You usually know this already from Step 1's answer and how the user framed the request; only ask explicitly if it's genuinely unclear. Match the interview to the answer:
- Small / one-off (a single change, likely near-done): keep it short. Scope in a sentence, the one change's in/out/rules, and Done-when. Skip the empty/null and constraints probes unless they obviously bite.
- Feature: the full sweep below, focused on that one feature.
- Project / multi-feature: full sweep, expect several feature blocks, and know this will likely trip the Step 5 size flag — so keep each block tight.
Over-interviewing a small change is as much a failure as under-speccing a big one.
2b — How to ask
- Discovery questions, one at a time. Open-ended elicitation ("what should this do?", "what are the rules?") gets better answers unbatched — ask, listen, follow the thread.
- Settled either/or choices may batch. Concrete decisions with known options (SQLite vs Postgres, REST vs GraphQL, which auth method) can go in one structured multi-question prompt. Don't drag a dozen binary choices out one at a time.
- You own "covered," scaled to size. Don't start writing until the areas that matter at this scale are covered — the user's "go ahead" does not override a real gap. But stop when more questions would only produce detail the builder doesn't need yet. For genuine unknowns, note an Open Question and move on rather than stalling.
2c — Probe these areas
Scale depth to 2a. For a feature on existing code, read the touched files first and probe integration points (existing names, call sites); for greenfield, probe the data shape and the stack.
- Scope — What does this do in one sentence? What does it explicitly NOT do? (push for at least two hard boundaries)
- Features — The distinct features/sub-systems. For each: input, output, rules.
- Done when — see 2d; the heart of the interview.
- Edges and errors — empty/null/zero inputs; failure modes; what the user sees when it breaks. Domain-specific failures (auth, partial state, concurrency) matter more than the generic ones.
- Constraints (skip if N/A) — hard technical limits (language, framework, performance); external deps (APIs, creds, env vars).
2d — Make every Done-when observable
This is the part that earns the spec. A criterion is observable if it names something you can run, inspect, or watch and get an unambiguous pass/fail. Reject anything you couldn't hand to inspector and have it judge. Rewrite vague ones with the user until they're concrete, then tag:
[automated]— a command or test judges pass/fail.[human-required]— only a person can judge (layout, copy, feel, complex UI state).
Push the left side to the right side:
| Vague (reject) | Observable (accept) |
|---|---|
| "login works" | "POST /login with valid creds → 200 + a session cookie; bad creds → 401 with {error}" [automated] |
| "handles bad input" | "submitting an empty cart returns 422 and writes no order row" [automated] |
| "the dashboard looks right" | "the 4 KPI cards sit above the fold at 1280px; hierarchy and spacing read cleanly" [human-required] |
| "it's fast" | "search returns in <200ms on a 10k-row table, timed in the test" [automated] |
If a criterion can't be made observable even after rewriting, it isn't a Done-when — it's an Open Question or out of scope.
2e — Brief-expansion (autonomous mode)
You have a written brief and no one to ask. Your job is to expand it into a complete, well-formed spec without inventing requirements — and to make every gap visible instead of papering over it.
- Extract what the brief states. Pull scope, features, inputs/outputs, rules, and any criteria directly given. Use the brief's own terms; for a feature on existing code, read the touched files and use the names already there.
- Cover the same areas as 2c — scope boundaries, each feature's input/output/rules, edges and errors, constraints. For each area the brief answers, write it down. For each area it leaves open, go to step 3.
- Assume, document, surface — never silently guess. When an area is unspecified and you need it to write a buildable spec, take the most conventional, lowest-surprise default, write the spec against it, and record it under
## Assumptions(Step 3) stating what you assumed:"Auth method unspecified — assumed email+password session, not OAuth. Confirm if wrong." An Assumption is a default that is low-surprise and cheap to change if wrong — the spec is fully buildable against it; it just wants a human's nod. It does not block the build.
- A fork that changes the build is an Open Question, not an Assumption. A genuine either/or the brief doesn't settle that would send the build down a different road (SQLite vs Postgres, sync vs async, a missing core data model) — or any default that would be expensive to undo once built on — you must not quietly default. Record it under
## Open Questions. This is the only kind that blocks: the orchestrator halts for a human rather than building the wrong thing.- The test for which bucket: if this default turns out wrong, is it a cheap edit or a partial rebuild? Cheap → Assumption (the build proceeds, the human reviews it after). Rebuild, or it forks the architecture → Open Question (halt first). When genuinely unsure, treat it as an Open Question — the cost of a needless halt is a question; the cost of a wrong fork is a rebuild.
- Then apply 2d — make every Done-when observable — to the criteria you extracted or assumed, exactly as interview mode does.
The discipline: a thin brief produces a complete spec with a clear ## Assumptions list (defaults to confirm) and, only where a real fork remained, an ## Open Questions list (which halts). Neither hides a guess; both make the brief's thinness visible. Step 6 reports READY · ASSUMPTIONS: N when only assumptions remain (the build proceeds), or OPEN_QUESTIONS: N when a fork must be answered first (halt).
Step 3 — Write the spec
If updating an existing spec: overwrite it in place. Prior versions live in git history.
Write to Planning/specs/[feature]_spec.md. Create Planning/specs/ if it doesn't exist.
Use this format exactly. Inspector reads the literal **Done when:** heading and the [automated] / [human-required] tags — keep them exact.
# Spec: [Feature Name]
[One paragraph: what this does and why.]
## Scope
- Does: ...
- Does NOT: ...
## Feature: [Name]
[What it does.]
- Input: ...
- Output: ...
**Done when:**
- [observable criterion] `[automated]`
- [observable criterion] `[automated]`
- [criterion only a human can judge] `[human-required]`
<!-- Repeat a Feature block per feature. Every feature must have a Done when block. -->
## Assumptions
<!-- Autonomous mode: low-surprise, cheap-to-change defaults you made where the brief was silent.
The spec is built against these; they are non-blocking — listed for a human to confirm/override.
Remove the section if none (interview mode usually has none). -->
- [What was unspecified] — assumed [default]. Confirm if wrong.
## Open Questions
<!-- A genuine fork you could NOT safely default — answering it changes the build, or a wrong guess
means a rebuild. This section blocks. Only include if such a fork remains; remove if none. -->
- [Question that must be answered before building]
Step 3b — Fill the pending contract (first spec on a fresh scaffold)
If CLAUDE.md carried [pending — architect] placeholders for Stack and Commands (noted in Step 1), fill them now — this is the one time architect writes to the contract. Scaffold left them deliberately: the stack and how-to-run are consequences of what you just specced, which is your call, not scaffold's.
Replace only the placeholders (never touch the rest of scaffold's structure):
- Stack — the language/framework the spec implies.
- Test command — how this project's tests run.
- Run/demo command — how to launch it so behaviour is visible. Must be real — inspector depends on it.
- UI evidence tool — only if the spec calls for a browser UI, add the Commands line
- UI evidence tool: playwright (python). inspector greps the literalUI evidence toolkey — keep it exact.
Where the stack or how-to-run isn't settled:
- Interview mode — ask, one question at a time, same as any other gap.
- Autonomous mode — you can't guess a run command into existence. If the brief doesn't settle the stack (or a UI choice that changes it), that's an Open Question (Step 2e) — record it and let it halt the run, exactly as for any other unresolved fork. A guessed command inspector later can't run is the failure this prevents.
An already-filled contract (an existing project, a later feature) — leave it untouched; only fill placeholders.
Step 4 — Write the decision log
Write docs/decisions/[feature]_YYYY-MM-DD.md:
# Decisions: [Feature Name]
Spec: Planning/specs/[feature]_spec.md
Date: YYYY-MM-DD
- [What was decided] — [why, and what was rejected or ruled out]
- [What was decided] — [why, and what was rejected or ruled out]
Only record choices that weren't obvious — constraints accepted, alternatives rejected, scope boundaries drawn. If nothing was hard to decide, keep it short. Do not pad.
Step 5 — Validate before handoff (possible endpoint)
Two checks on what you just wrote. The first is structural and runs identically in both modes; the second resolves differently depending on whether a human is present.
5a — Structural self-check
Mechanical checks on your own output. You wrote the spec, so fix what you can; surface only what you genuinely can't resolve without input.
- Every
## Feature:block has a**Done when:**section. A missing one means you under-specced — write it, or if you lack the information, record the gap as an Open Question. - Every Done-when line carries exactly one tag:
[automated]or[human-required]. No untagged criteria. ## Scopehas aDoes:and at least one hardDoes NOT:.- No template placeholders or empty sections left behind.
- Every gap the brief left is accounted for in
## Assumptions(a low-surprise default you built against) or## Open Questions(a fork you couldn't safely default). In brief-expansion mode this is load-bearing — these two lists are the only signal homeowner (or, in interview mode, the human) gets about where the brief was thin and what you did about it. A gap filled by a guess that appears in neither list is a silent guess — the thing this whole path exists to prevent.
This pass is structural only — is the spec well-formed? Whether each criterion is genuinely observable is homeowner's judgment in autonomous mode (its spec self-review), the human's in interview mode. Don't grade your own observability call here; just guarantee the shape is right.
5b — Size check
Measure what you produced:
- Whole project spec — number of
## Feature:blocks and total line count. - Largest single feature — line count of the biggest
## Feature:block.
If the project spec exceeds 6 features or ~500 lines, or any single feature exceeds ~150 lines, it's flagged. Do not restructure — architect never splits specs. Thresholds are tunable defaults, not law. Resolve the flag by mode:
-
Interview mode — ask the user one question, framed around their forecast, not the line count:
"This spec is getting large ([what tripped — e.g. '7 features', 'the X feature is ~180 lines']). Are we close to done here, or is this heading toward a big project? If it'll keep growing, it's worth planning a restructure later — splitting into per-feature specs and pulling shared terms/data models into a reference tier. I won't do that now; I just want to know whether to flag it as pending."
Near done → note nothing, proceed. Big project → record a one-line Pending: restructure note in the decision log so it isn't lost.
-
Autonomous mode — you can't ask for a forecast. Record the Pending: restructure note in the decision log with what tripped, and surface it in the handoff. The size flag never blocks the build — it's a scaling forecast, not a buildability defect, so it does not go to Open Questions (that would halt the loop over a non-problem).
This check is the only place architect touches the grow-then-split lifecycle. In interview mode it's a possible endpoint (a big project may pause here to plan a restructure); in autonomous mode it's never an endpoint — record and continue.
Step 6 — Report and hand off
Architect produces artifacts and reports a status. It never invokes the next stage itself — the caller sequences. In interview mode the caller is the user; in autonomous mode it's the orchestrator. Same artifacts, different reader.
Interview mode — tell the user:
- Review the spec at
Planning/specs/[feature]_spec.md - Review decisions at
docs/decisions/[feature]_YYYY-MM-DD.md - Resolve any Open Questions before proceeding
- (First spec on a fresh scaffold: confirm the Stack/Commands you filled in
CLAUDE.md) - Run foreman to generate the blueprint from this spec
Autonomous mode — emit a routable status, then stop. Do not review your own spec or call foreman — the spec review and the next-stage call are the orchestrator's job (convention-coupled, not call-coupled). Report:
- Spec:
Planning/specs/[feature]_spec.md - Decision log:
docs/decisions/[feature]_YYYY-MM-DD.md - Contract: if this was the first spec on a fresh scaffold, note you filled CLAUDE.md's pending Stack/Commands (Step 3b).
- Status:
READY— structural self-check passed; no Assumptions and no Open Questions, orREADY · ASSUMPTIONS: N— buildable, but N low-surprise defaults were assumed (from## Assumptions); list them verbatim. Non-blocking — the orchestrator proceeds and surfaces them for the human to confirm or override after. Use this only for cheap-to-change defaults (Step 2e); a fork belongs below.OPEN_QUESTIONS: N— N genuine forks remain (from## Open Questions); list them verbatim. This is the only blocking status — the orchestrator halts for a human, and foreman would refuse the spec anyway.+ SIZE_FLAGGED— append to any status when 5b tripped a threshold. Informational; never blocks.
Then stop. The orchestrator reads the status and decides what runs next — architect's job is done at the artifact.