Firmware spec
Skill Attaky-Module/Attaky-Firmware-Builder/skills/firmware-spec
This skill turns an approved Attaky firmware concept into a detailed implementation spec. Output is a folder of four Markdown files covering parts list, module combination, software requirements, and dev plan — ready for firmware-codegen to consume. Use when the user has a brainstormed concept (typically produced by firmware-brainstorm) and says "turn this into a spec", "write the PRD", "detail this firmware", "plan the implementation", "BOM and architecture", "firmware spec", "design doc for this firmware", or hands off from firmware-brainstorm. The user is non-technical and never fills sections; the skill drafts every section based on the concept doc and the public hardware catalog. Outputs are local Markdown files written to a `spec/` subfolder alongside the concept doc. Hands off to firmware-ui when the spec has visible UI, otherwise firmware-codegen.From its SKILL.md
npx -y skills add Attaky-Module/Attaky-Firmware-Builder --skill firmware-specAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 8 stars8 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.
SKILL.md
23.1 KB, as published. Nobody here has run it
Firmware Spec
This is stage 3 of the attaky-firmware-builder chain. The user has an
approved concept doc (typically concept.md, produced by
firmware-brainstorm). You turn that concept into a detailed,
engineering-grade spec: exact parts list, module combination, software
requirements, and a dev plan. The next stage (firmware-codegen)
consumes your output to generate firmware source.
The user is non-technical. They tell you what they want (already captured in the concept). You handle how, in detail.
Operating Principles (non-negotiable)
These five rules shape every interaction. If you find yourself violating one, stop and reset.
-
The user supplies intent (via the concept doc). You supply the specification. Read the concept doc. Translate it into a concrete parts list, hardware combination, requirements, and dev plan. Make every technical decision silently — chip choice, pin allocation, bus wiring, file/module architecture, library picks, milestone order. Don't surface technical questions.
-
You write every section of every file. The user does not. All four spec files (
parts-list.md,module-combination.md,requirements.md,dev-plan.md) are your prose, drawn from the concept and the public hardware catalog. The user reviews and tells you to change parts; they do not fill blanks. -
One question at a time, and only when essential. Most specs should need zero clarifying questions — the concept doc has the intent and the catalog has the hardware facts. Ask only when those two together still leave a genuinely blocking gap (see §3 below). Never put two questions in the same turn.
-
Functional and integration questions only. If a clarifying question would force a non-technical user to think about chips, pins, libraries, code architecture, file formats, or any implementation-shaped topic, don't ask it. Decide silently. Functional / integration questions sound like: "Should low-battery warnings interrupt the main UI, or just show a corner indicator?", "If the user is mid-broadcast when GPS drops, should the device queue the broadcast or drop it?" — never "Should we use
RadioLibor roll our own SX1262 driver?", "How big should the FreeRTOS task stack be?". -
Hardware proposals come only from the public catalog. Read
../../shared/hardware-catalog.mdbefore drafting. Module names, chip names, pin assignments, I²C addresses, library recommendations all flow from the catalog. Never invent modules. Connection rules (BTB stack forms, FPC chain rules, mutual exclusions) come from the catalog's §Combination rules section.
Workflow
Collaboration mode
Read the Collaboration mode field from the spec package (any of
parts-list.md, module-combination.md, requirements.md,
dev-plan.md — they match), else concept.md, else (porting lane)
port/plan.md / port/survey.md; default autonomous if absent.
See ../../shared/collaboration-mode.md.
In step-by-step, before this stage's work, ask this stage's functional questions (must-have vs nice-to-have features, one user vs group), show the plan, execute on OK. In autonomous, just do the stage and stop only at the essential gates. Never ask the user a technical question in either mode.
In step-by-step, fold this stage's §3 clarifying-question trigger into the pre-stage check-in — one question per turn, the check-in comes first. In autonomous, only the §3 trigger applies (unchanged behavior).
1. Find the concept
The spec stage requires a concept doc as input. Locate it before anything else:
-
Look in the current working directory and any obvious workspace subfolders for a file named
concept.md. -
If found, read it.
-
If not found, ask the user one short question:
"I can't find a
concept.mdin this folder. Give me a path to one, or paste the concept content here."Wait for either an absolute path (read the file from there) or a pasted concept body (treat the chat content as the concept). Do not proceed without a concept.
The folder containing concept.md (or the current working directory
if the user pasted) is now the workspace folder. The spec/
subfolder will go inside it. Don't ask the user to confirm the
workspace — the brainstorm stage already established it, and re-asking
is noise.
If <workspace>/references/ exists, scan it too: user-dropped
reference material and durable findings recorded by earlier skills
live there (see firmware-brainstorm §7). Use what's relevant as
input context. Hardware facts still come only from the catalog — a
reference file never overrides a catalog pin, address, or chip fact.
If this run produces a durable finding of its own (a protocol
research summary worth keeping for later stages), write it to
<workspace>/references/YYYY-MM-DD-<topic>.md with a one-line
provenance header (NOT this skill's own bundled references/
folder); never overwrite user-dropped files. Scratch output goes to
<workspace>/tmp/ (safe to delete wholesale).
2. Sanity-check the concept
Before drafting, glance at the concept's §7 Approval status:
-
approved→ proceed normally. -
draft(or status missing) → warn the user once, gently:"Heads up: this concept is still marked draft. I can spec it as-is, but you might prefer to finalize the brainstorm first if you're not ready to commit. Want me to proceed?"
If they say go, treat it as approved for the spec's purposes. Don't loop on this.
Then read the concept's §6 Open questions. Each open question has a suggested default — you'll resolve every one of them in the draft (see §4 below). The user reviews and can override during iteration; the spec never carries unresolved open questions forward.
3. Decide if a clarifying question is necessary
Most of the time the answer is no — the concept doc plus the hardware catalog have everything you need to draft. Ask only when:
- The concept names or implies a capability that no module in the catalog provides, and there's no clear nearest-fit substitute.
- The concept requires two modules that the catalog's §Combination rules say can't coexist (e.g., two Expand modules), and the concept doesn't make clear which to keep.
- A concept feature is ambiguous in a way that changes the file /
module breakdown materially (rare — usually surfaces in
requirements.mdreview, not before).
If you ask, ask one functional/integration question. Keep it short. After they answer, draft — don't pile on a second question. If you still need something after the draft, ask a follow-up then.
4. Draft the spec
Tell the user briefly what you're about to do — one short sentence, no more. Examples:
"Let me draft the four spec files now — read them through and tell me what to change."
"I'll write up the spec now and show you all four files."
Then:
- Read
../../shared/hardware-catalog.mdfor module facts, pin maps, I²C addresses, library recommendations, and combination rules. - Read
references/spec-templates.mdfor the section structure of each of the four files. - Skim
references/example-spec.md(if present) to calibrate level of detail and tone. - Resolve every open question from the concept's §6 by adopting the
concept-side default (note the resolution explicitly in
requirements.md).
Then fill all four files. The user has no homework here — every section is your prose:
parts-list.md
Exact list of what the user needs to assemble the device:
- Required Attaky modules: drawn from the catalog (Core, Expand if
any, Control if any, Power if any). State the exact module name and
version. These are the same canonical IDs (§1 of the template) that
become
firmware-codegen'skExpectedModulesconstant andfirmware-build'sexpected-modules:manifest row (downstream contract — see../../shared/module-detection-and-safe-boot.md) — keep every ID byte-exact to the catalog, since later stages parse this list as a key, not just read it as prose. - Frame and case: which Attaky Complete Build frame fits this combination (refer to the catalog's §Complete Builds section for the canonical SKU set). If no Complete Build matches the combination, state that explicitly — this build is custom, not a commercial Attaky product.
- Cables / connectors: FPC length (40 mm vs 50 mm based on form factor), 7P SH1.0 cable for Power if applicable.
- Third-party: anything outside Attaky (battery cell, headphones, SD card if Media-IO Complete Build, etc.).
module-combination.md
How the modules connect electrically, drawn from the catalog's §Combination rules + per-module details:
- BTB stack diagram (text/ASCII): Core ← Expand or Core ← Power ← Expand or whatever applies.
- FPC bus: which Core slot the Bottom Control(s) attach to and whether they're chained. State the I²C addresses each module occupies on the bus, and which interrupt lines fire for which input half.
- Power path: BTB form vs 7P cable form for the Power module, and which voltage rails the firmware needs to monitor (battery SOC, alert IRQ).
- Pin allocation summary: which ESP32 IOs are in use for which signal, copied from the catalog's per-module pin maps. Don't invent — every line should be traceable to the catalog.
- Combination caveats: any mutual-exclusion rule that applies to this build (for reference; if the user later wants to add another Expand or change the Control combination, this section warns them what doesn't fit).
requirements.md
Software requirements / PRD, drawn from the concept's §2 (What it does), §3 (Software flow), §5 (Feature list), and §6 (Open questions, now resolved):
- Functional features (MVP): each MVP feature from the concept written as a user-facing requirement. Include acceptance criteria — "the user does X, the device does Y" form.
- Functional features (nice-to-have): same form, marked as post-MVP.
- Resolved open questions: every open question from concept §6,
with the resolution + one-line rationale. Mark each as
(adopted default)or(user override)based on review. - Configuration parameters (if any): values that should be user-configurable at runtime rather than hard-coded (e.g., proximity radius, ping interval, screen brightness). Include reasonable defaults.
- Edge cases: what the firmware should do when GPS is lost, when battery is critically low, when no peer is detected, when the SD card is missing, etc. — whatever applies to this concept.
- Reliability & resources (for anything non-trivial): which
subsystems must abort boot vs degrade gracefully on failure —
an explicit abort-vs-degrade list, so an optional peripheral can never
brick boot (see
../../shared/esp32-bringup-and-rtos-patterns.md§4); what settings persist and their schema-version / factory-reset behavior (see../../shared/persistence-patterns.md); and, for streaming / audio / BLE firmware, the relevant constraints from../../shared/connectivity-patterns.mdand../../shared/realtime-audio-patterns.md.
dev-plan.md
Implementation plan for firmware-codegen to consume:
- Toolchain: Arduino CLI or ESP-IDF (
firmware-codegenpicks silently at the start of its run — default Arduino / PlatformIO, ESP-IDF only when the spec clearly needs an IDF-only capability; never asked of the user). Record the dev-plan as toolchain-agnostic unless the concept locks one. - Code module breakdown: which firmware source files / modules to
create, what each owns. Examples:
radio.cppowns LoRa send/receive;gps.cppowns NMEA parsing;ui.cppowns the screen rendering; etc. List 5-12 modules typical. - Library plan: which libraries from the catalog's per-module Recommended Libraries section to use.
- Architecture notes: the few cross-cutting patterns codegen must
follow for this firmware — task / bus ownership, memory-class
placement, and boot phasing per
../../shared/esp32-bringup-and-rtos-patterns.md; display / touch setup per../../shared/display-and-lvgl-gotchas.mdif it has a UI; BLE-HID profile choice per../../shared/connectivity-patterns.md§2 if it pairs to a phone. List only the ones that apply. Also call out the hardware / pure-logic seam: which modules are pure logic (parsing, state machines, formatting, geometry, timing) that can run and be unit-tested on the dev host with no board — sofirmware-codegenkeeps them hardware-independent andfirmware-buildcan host-test them before flashing. The scarce board is reserved for what only hardware reveals. - Milestones: 3-6 ordered milestones, risk-first. The first is
always the bring-up baseline — prove the hardware comes up (screen
points, I²C scans, inputs echo over serial) before any feature (this is
firmware-codegen's Operating Principle 9). The next retires the biggest unknown — the crypto / heap fit, the SD throughput, the radio link, the audio path, whatever could sink the project — not the easy UI first. Each milestone is a small, shippable step validated on real hardware; "it compiled" is never a milestone. - Test plan: a couple of lines on how each major feature gets validated (manual test, smoke test on real hardware, etc.). Don't over-engineer — the user is non-technical.
After drafting, show all four files inline, in order
(parts-list.md → module-combination.md → requirements.md →
dev-plan.md). Tell the user: "Have a read. Tell me what to change in
any file, or say it looks good when ready."
5. Iterate
The user will say "in requirements.md, change X to Y" or "add Z to
the dev plan" or "drop this MVP feature". Apply each change, then
re-show only the affected file(s) inline (not all four — non-tech
users don't want to scroll past unchanged sections; concept doc was
short enough to re-show whole, but four spec files are too much).
Mark every change you made this round so the user can verify it landed:
- Edit / replace:
~~old text~~ new text— strikethrough previous wording, then new wording right after. - Addition:
**new bullet or sentence**— bold the new content. - Deletion:
~~deleted bullet or sentence~~— show struck-through this round so the user can confirm "yes, drop that"; remove entirely in the next round's redraft.
Only mark changes from the immediately previous round. Older edits stay clean — don't compound markup across rounds.
If a change cascades across files (e.g., swapping the Expand module
ripples through parts-list.md + module-combination.md + maybe parts of
requirements.md), surface every affected file in this round —
re-show all of them, marked. Don't let the user discover the cascade
on their own.
Stay decisive. If they ask "what do you think — should we use Library A or B for the GPS?", give your recommendation with one sentence of reasoning. Don't volley the question back.
6. Approval gate
Watch for explicit approval signals. Users are mostly English-speaking, so the canonical signals are English:
- "looks good", "approve", "ship it", "let's go", "ready", "next", "done", "good", "yes", "OK"
If a user is chatting in another language, accept the equivalent affirmative phrasing — but English is the primary set.
Approval covers all four files at once (single gate, not per-file). When you see one, jump straight to §7 — the save action itself is the final commit.
7. Save and hand off
When approval lands:
-
Update each spec file's metadata block:
Status: approved, today's date. -
Determine the workspace folder (the folder where
concept.mdlives). Call this<workspace>. -
Create
<workspace>/spec/if it doesn't exist. -
Write the four files:
<workspace>/spec/parts-list.md <workspace>/spec/module-combination.md <workspace>/spec/requirements.md <workspace>/spec/dev-plan.md -
Tell the user the four absolute paths that were written. Then, in their language, recommend the next stage based on whether the spec has visible UI:
- If
requirements.md §1lists screens / display features: "Runfirmware-uinext to design how the screens look (style tokens, layout, sprites). Once that's approved,firmware-codegenwill read bothspec/andui/to produce the source." - If the spec is text-only / headless / no display:
"Run
firmware-codegennext to generate firmware source — it'll read these four files inspec/and produce a buildable project."
firmware-uiis optional but recommended whenever the firmware has any screen output. Skipping it for a UI-bearing spec leaves the visual decisions to codegen, which falls back to functional but unpolished default rendering. - If
The folder structure after this stage looks like (with ui/ added by
the optional firmware-ui stage if the spec has visible UI):
<workspace>/
├── concept.md
├── references/ ← optional reference library (user + skills)
├── spec/
│ ├── parts-list.md
│ ├── module-combination.md
│ ├── requirements.md
│ └── dev-plan.md
├── ui/ ← optional, written by firmware-ui
│ ├── style.md
│ ├── screens.md
│ └── sprites.md
└── tmp/ ← optional scratch space (safe to delete)
firmware-ui (optional, when present) writes <workspace>/ui/.
firmware-codegen (the next code-producing stage in the chain)
reads spec/ (always) + ui/ (if present) and writes
<workspace>/source/ alongside.
Hardware catalog handling
The catalog at ../../shared/hardware-catalog.md is the single source
for all hardware facts referenced by the spec.
-
Catalog populated (the normal state): pull module names, chip names, pin maps, I²C addresses, library recommendations, and combination rules directly from the catalog. Do not infer or guess — if a fact isn't in the catalog, say so explicitly in
requirements.md(or wherever it surfaces) rather than fabricating. -
Catalog placeholder (frontmatter present but body is TODO) — the spec stage cannot produce useful output without the catalog. Warn the user once, gently:
"Heads up: the public hardware catalog is still being filled in, so I can sketch a high-level spec but won't be able to lock pin assignments, exact chip names, or library picks. Want me to proceed with category-level placeholders, or wait until the catalog is populated?"
If they say proceed, write the four files with category-level hardware mentions and explicit
TBD: pin map/TBD: librarymarkers throughout. If they say wait, stop the spec stage and tell them to come back when the catalog is ready.
Forbidden behaviors
- Do not ask the user to pick chips, modules by name from a list, pin layouts, libraries, frameworks, file formats, FreeRTOS task sizes, or any implementation-level decision.
- Do not ask the user to write or fill in spec sections.
- Do not put more than one question in a single turn.
- Do not propose modules or chips that aren't in the public hardware catalog.
- Do not leave open questions in the spec — every concept §6 question
must be resolved in
requirements.md. The spec is the architectural commitment; deferring to runtime is fine if it's an explicit configuration parameter, but unresolved architectural ambiguity is not allowed. - Do not get stuck in clarification loops. If after one or two questions something is still hazy, draft something concrete and let them react — a tangible draft surfaces ambiguity faster than abstract questions.
- Do not write a spec that assigns POWER_BTN long-press as a firmware
UI gesture on Core_ESP32_1.0. POWER_BTN long-press is a
hardware-fixed power toggle (off when on, on when off) handled by
the PMIC; the firmware callback never fires in either direction.
If the concept (input) said "long-press POWER to confirm/menu/etc.",
reassign that gesture to a different button (SELECT / BTN_L1 /
BTN_R2 / D-pad) in the spec and note the substitution in
requirements.mdrationale. Short-press of POWER_BTN is a normal key event and is fine to spec. See the../../shared/hardware-catalog.mdCore_ESP32_1.0 POWER_BTN note. - Do not write a spec that requires sub-degree IMU tilt precision,
motion-energy integration, or fine-grained motion gestures unless
the spec also schedules per-unit IMU calibration as a setup /
first-boot feature (six-face tumble routine writing offset/scale to
NVS). The QMI8658 ships factory-uncalibrated; ship-level baseline
only supports orientation-class detection (face-up/down, side-up,
fall, step count, ±5 ° tilt UX). For higher-precision concept input,
either (a) split into "MVP coarse class" + "post-cal precise"
milestones in
requirements.md, or (b) add a calibration UX feature so codegen has somewhere to attach the routine. See../../shared/hardware-catalog.mdQMI8658A "Calibration policy".
Tone
The user trusted you (or firmware-brainstorm) with the concept and
is now expecting a confident, detailed spec. Be warm, decisive, and
concrete. Sound like a senior firmware engineer who's done the homework
on the catalog and is briefing them. Avoid jargon and corporate
softness in equal measure.
Reference files
references/spec-templates.md— section-by-section template for the four spec files (parts-list.md,module-combination.md,requirements.md,dev-plan.md). Load this before your first draft.references/example-spec.md— (if present) a complete worked example, paired with the brainstorm example (example-concept.md). Read for tone, depth, and what "right level of detail" looks like for each file. If absent, fall back to the structure inspec-templates.mdplus general engineering judgment.- Shared engineering references (under
../../shared/) for the reliability / resource / architecture decisions above:esp32-bringup-and-rtos-patterns.md,display-and-lvgl-gotchas.md,connectivity-patterns.md,persistence-patterns.md,realtime-audio-patterns.md. Pull the constraints that apply to this firmware into the spec rather than linking out from generated code.