main
Download ZIP Propose a change
Name Last commit message Last updated
assets Publish 0.5.0 · Caleb
bin Publish 0.5.0 · Caleb
docs Publish 0.5.0 · Caleb
flows Publish 0.5.0 · Caleb
runs Add the Compute Module 5 run of version 0.4.0: report, evidence images, audit sheets and KiCad copy · Caleb
screenshots New hero: copper sorted into nets · Caleb
skills Publish 0.5.0 · Caleb
src Publish 0.5.0 · Caleb
tools Publish 0.5.0 · Caleb
videos Version 0.3.0: new copper reader, dome via filter, every layer read from the photos, net evidence, measured confidence;… · Caleb
.adomignore Add the Rust source, flow definition, assets and install scripts · Caleb
.gitignore Keep the bin folder out of the ignore list so the package ships its binary · Caleb
build.sh Publish 0.2.0 · Caleb
Cargo.lock Publish 0.5.0 · Caleb
Cargo.toml Publish 0.5.0 · Caleb
install.sh Publish 0.2.0 · Caleb
LICENSE Add the Rust source, flow definition, assets and install scripts · Caleb
package.json Publish 0.5.0 · Caleb
page.json Set visibility: public · Caleb
README.md README: photo best practices · Caleb
uninstall.sh Publish 0.2.0 · Caleb

AI Flow: Reverse Engineering

Download the 1080p video, which shows the photos better than the player copy, or the full run with every board, audit and recorded view.

Photos of a PCB in, a KiCad copy out: the parts identified, the functional blocks named, every island of copper traced from the photos, the connections nobody can see listed and left unrouted with their evidence, the layer count stated from what is known, two confidence scores, and the tests that would settle what is still unknown.

It is a standalone Rust program. It measures from the photos, generates the board and checks. Routing the hidden connections is an optional later stage. The AI running it supplies what takes judgement: what a part is, what a block does, what a net is called. Every claim carries an evidence tag: SEEN, MEASURED, DATASHEET, INFERRED or UNKNOWN.

Status: version 0.5.0, tested on thirteen boards, not a finished result. The flow now runs from a folder of photos to its last file without stopping for a person. It places parts well. It does not yet recover a board's connections: no test board came out as a copy you could build from, and every run says so in its own report. The section below says what to expect. docs/status.md lists every known gap.

Taking photos for the best results

The program reads copper, vias and markings pixel by pixel, so the photos decide most of the result. Photograph both faces of the board the same way and pass every photo to init --photos unsorted.

# Topic Do Avoid Why it matters
1 Backlight Shoot each face with a strong, even light behind the board (a light pad, a tablet showing a white screen, or a window), room lights off, at the same distance as the close-ups Backlight that is uneven, or so bright that the picture turns white On two-layer and thin boards the copper shows through as dark shapes against the light: tracks, pours and vias stand out clearly whatever the mask colour. This is the biggest single improvement for reading copper
2 Detail Shoot close enough for 60 pixels per mm or more of board: a phone about a hand's width away (10 to 15 cm), or a macro lens Whole-board phone shots only (about 16 pixels per mm) Tracks and the gaps between them must be several pixels wide to be read; the boards that read best were photographed at 65 to 85 pixels per mm
3 Coverage 6 to 8 close-ups per face, each overlapping its neighbours by about a third, covering every edge Gaps between shots, or tiles that only just touch The close-ups are stitched into one image per face; the overlap is how they are lined up
4 Overview One photo of each whole face, the board filling most of the frame with a clear margin all round A board cut off at the frame edge Gives the board outline and fills any gap the close-ups missed
5 Both faces Photograph top and bottom the same way, at the same detail A sharp top and a rough bottom Vias and through-hole joints are confirmed by seeing them from both sides
6 Camera angle Straight down, the phone parallel to the board, the board lying flat Tilted shots, wide-angle shots from very close A slanted shot skews the stitched image and throws the two faces out of line
7 Focus Sharp over the whole frame, edges included; focus on the board surface Blur, or focus on a tall part instead of the board Blur merges neighbouring tracks into one
8 Front lighting Soft, even light: a ring light, a light box, or daylight from a window Flash, a single bright lamp, hard side light Glare looks like silkscreen and hides tracks; long shadows cut tracks
9 Glare Angle the light so no bright reflections sit on the board; a polarising filter helps Shiny reflections on pads, chips and mask Reflections are read as metal or print
10 Background Plain, matte, and a colour unlike the solder mask (mid grey suits most boards; black suits light boards) Patterned cloth, or a colour close to the mask (teal under purple, green under green) The board edge is found by the mask colour
11 Scale Nothing extra when the board has a 2.54 mm header, a hole row or a chip of known size; otherwise lay a ruler flat against the board edge, at board height, in at least one top photo A ruler propped up, or lower than the board Scale comes from features of known size; a ruler out of the board's plane gives a slightly wrong scale
12 Board condition Clean and unplugged, no cables or modules attached, no stickers over parts Glue or coating over markings, cables lying across the board Covered parts and tracks cannot be read
13 Markings Close-ups sharp enough to read chip and resistor markings Markings in glare or shadow Part identities and values come from the markings
14 Files The original camera files as JPG or PNG, in any order (set an iPhone to "Most Compatible" or export HEIC as JPG) Edited, cropped, rotated, filtered or stitched photos; HEIC files The program reads JPG and PNG only, and sorts, rotates and stitches the photos itself from their original pixels
15 Video Still photos Video as the only input Video frames are compressed and often blurred; video is not accepted as input

Optional extras. They add information and are never required.

# Extra What it adds
A A second front-lit set with the light from the opposite side Glare and shadows move and copper does not, so the two can be told apart
B Multimeter continuity checks from the run's bench plan Settles connections no photo can show
C An X-ray or an edge cut of the board The only evidence for inner layers

Quick check before sending. Zoom into one close-up until a single track fills the screen. The track and the gaps beside it should have clean, sharp edges. If they do not, move closer and shoot that area again.

Version 0.5.0: what to expect from a run

Eleven boards were run from photos alone, from a 2-layer launchpad to a 6-layer control board, on green, red and blue solder mask. Seven of them were then graded against their real designs (KiCad files, one Eagle board through KiCad's import, one placement list). The designs were never an input to a run.

What every run delivers. A KiCad board and project, a KiCad schematic with real symbols and datasheet pin names, a picture of the copper coloured by how well each net is proven, a picture per net, a list of bench tests, a report with a measured confidence line, a bench plan (an optional set of probes you can take and feed back), and a two minute narrated video made from the run's own files.

Net confidence picture of a TI MSP-EXP430F5529LP run: top copper in blue where a net was seen joined, bottom face marked not read

The net confidence picture from the TI MSP-EXP430F5529LP run. Blue copper is joined to its net by copper that was seen. The reader merged much of the top face into one area, and the bottom face is marked as not read: nothing is claimed there. Download this run's video.

Strong points

  • Where the parts are. On whole-board photo sets the placed parts sit 0.08 to 0.44 mm (median) from their real positions, and 78 to 99 percent of the placed parts are real parts. On six of the seven graded boards 66 to 96 percent of the real parts were found; the seventh, photographed in part and on one face, reached 35 percent.
  • The outline and the scale. The board size came out within 0.2 to 0.8 mm on the four green boards photographed whole and graded. On the red board it came out 2.5 to 2.8 mm too large.
  • Vias, on green boards with open vias. On the USB hub board 90 percent of the real vias were found and 99 percent of the kept ones are real.
  • It says what it does not know. Every claim carries a tag (SEEN, MEASURED, DATASHEET, INFERRED, UNKNOWN), a face that could not be read is marked not read, and the confidence score is the lowest category, measured by auditors who did not make the run. Planted false claims void an audit sample when an auditor accepts one.
  • It finishes. auto runs every step a program can run and stops only where judgement is needed, with the exact instruction.

Weak points

  • The connections. Of the pin pairs a run puts on one net, 23 to 39 percent are right, and it finds 0.2 to 22 percent of the real ones. Independent auditors judged 8 to 31 percent of sampled connection claims right. The copper reader merges neighbouring copper into large areas on photos stitched from close-ups, so nets taken from copper are few and often wrong.
  • Nets from the pinouts help, and are new. Building nets from what each chip is, which way round it sits and its datasheet pinout, with copper only confirming, raised the USB hub board to 87 percent of stated pin pairs right (7 percent of the real ones found). This is in 0.5.0 and needs the chips identified and their pin tables entered.
  • The part finder needs help. On most boards the AI running the flow read the parts from the photos and entered them; the program's own finder proposes few whole parts.
  • The schematic is a parts sheet. Symbols and pin names are right, but where nets are weak the pins end in labels marked ? and passives stand unconnected.
  • Vias under solder mask, and on red or blue boards, are not read. Seven of the eleven runs kept no vias at all.
  • The layer count is never stated. A run gives a minimum from what the photos show. No minimum was above the real count, and on six of the seven boards whose stackup is known the real count is higher (table below).
  • The copper audit cannot be judged on stitched photos. Five audit samples were voided by planted claims, and careful auditors answered "cannot tell" on most points.
  • Faces are laid on each other by the outline alone on three boards and not at all on one, so a top to bottom connection there is not trustworthy.

The eleven boards. Unpublished designs are described, not named.

Board Real layers Layers the run stated Parts found / placed parts real Pin pairs right / found Vias found
1 Control board, 160 x 45 mm 4 at least 2 66% / 89% 23% / 22% 0 of 134
2 Battery monitor evaluation board not known at least 4, inferred not graded
3 Raspberry Pi 5 not published at least 4, inferred not graded
4 MOSFET driver board 2 at least 2 95% / 87% 24% / 13% 33%
5 Automotive Ethernet switch 4 at least 2 96% / 96% 30% / 4% 0 of 314
6 Sequent Microsystems 16 inputs HAT not published at least 2 not graded
7 TI MSP-EXP430F5529LP, red 2 at least 1 70% / 78% 39% / 3% 0 of 444
8 Earth People Technology MAX V board, blue not published at least 1 not graded
9 Battery charger board, two partial photos 4 at least 2 67% / 84% (placement list only)
10 USB 2.0 hub board 4 at least 2 75% / 99% 38% / 0.2% (87% / 7% with nets from the pinouts) 90%
11 Control board, one face, partial photos 6 at least 1 35% / 67% 23% / 1% 0 of 640

Every run's own confidence line read between 0.0 and 4.1 of 100 against a target of 90. That is the honest figure: a copy is as trustworthy as its weakest category, and connectivity or copper is near zero on every board.

Use it today for a placed, scaled KiCad starting point with the parts identified, a clear picture of what the photos do and do not show, and a list of the measurements that would settle the rest. Do not use it yet for a netlist or a board you intend to build without checking every connection.

Version 0.4.0: a second board, and what the audits found

The second board is a Raspberry Pi Compute Module 5, from ten photos. Audits of its first complete run judged more than half the placed parts wrong, so the program was corrected and the run repeated from the same photos.

Fault the audits found Change in 0.4.0
Chip passives paired across neighbours detect parts reads chip passives body first
parts snap moved small parts up to 0.95 mm onto neighbours The reach follows the part's own size
Chip parts one size too large The size is settled by which pads fit the photo's metal; ties go to the smaller part
Real vias beside pads dropped A via stays when the photo shows board all round it; every dropped one is listed with its reason
Chip markings read as copper, dark spots in print read as vias Nothing on a part's top is copper; one-face vias in print or on a part's top are dropped
Audit claims no photo could settle ("is on net X") Claims state one join a crop can show; what shows no join counts as not correct
A KiCad check that did not run counted as 0 errors It counts as unknown: no stackup closes on it and the layers check fails
Routing took most of the run time for no information Routing stops after three stackups that leave the same connections open
CM5, independent audits First complete run 0.4.0 run
Placement, parts judged correct 43 of 98 41 of 47
Kept vias judged real sample not completed 43 of 51
Copper points judged correct sample voided 61 of 101
Copper and pad joins judged correct could not be judged 58 of 91
CM5 against a sealed answer key (totals only) Before 0.4.0 run
Parts found, of 479 46% 53%
Placed parts that are real 91% 98%
Median part position error 0.225 mm 0.107 mm
Through vias found 63% 89%
Copper match on bare mask, top / bottom 58 / 31% 58 / 32%
Pin pairs on one net that are right 10% 2%

The answer key for the CM5 is another person's reconstruction of the board (schlae/cm5-reveng), not the maker's design. The CM5 cannot be rebuilt from photos: eight inner layers are unknown and every connection under its three ball grid parts is hidden.

Known limits of 0.4.0. The passive reader's colour thresholds were read from the CM5 photos; on the Driver board's darker photo it finds few parts and invents some, so check its candidates by eye. The via reader still accepts some dark spots that have no ring (8 of 51 sampled). Copper is read right at about 60% of audited points on the CM5, because a fine track is 4 pixels wide in the 40 px/mm working frame. Ties in pad fit going to the smaller part, and passive angles going to the nearest 45 degrees, are tested but not audited.

CM5 run
    CM5 run    
The full result of the Compute Module 5 test: the report, the evidence pictures, the audit sheets and the KiCad copy. Read it to see what a dense ten-layer board gives from photos alone, and where each borrowed fact came from.
Open the run

Results on the Driver board (0.3.0)

The test case is a three-phase BLDC motor controller, from four photos and nothing else. All figures use KiCad's default rules.

Item Result
Parts 137 placed, 103 by their own pads on the photo
Blocks 11
Copper 828 pours and 2,588 tracks on both faces
Vias 1,329 kept, all from dome shading on the bottom
Against the photos Held-out copper IoU: bottom 0.873, top 0.823. Only 48% of the top is visible enough to score
Copper on a net No net: 7.6% of area, but 46.5% of track length
Nets 77, all still inferred
Tests 119
Layers Open New DRC errors Missing per KiCad Crossing seen copper
2 47 of 267 718 358 454 mm
4 43 of 253 475 340 384 mm
6, proposed 45 of 253 594 441 11 mm
8 45 of 253 602 452 8 mm

Checked against the real design

The real design was kept as a sealed answer key: never a flow input, never shown to an agent, totals only. The true layer count and outline were known while working, so neither of those is a blind result.

Measure 0.2.0 0.3.0
Vias that are real 42.4% 95.5%
Design vias found 25.8% 75.2%
Outline error, x / y -0.35 / -0.22 mm 0.04 / 0.03 mm
Copper match (IoU), top / bottom 61.4 / 80.2% 67.4 / 88.9%
Copper net purity, top / bottom 70.5 / 77.5% 76.1 / 85.9%
Copper with no named net, top / bottom 10.7 / 1.9% 13.8 / 5.9%
Pins on a consistent net 45.8% 48.4%
Parts found 84.7% 84.7%
Layer proposal 6, correct 6, correct

Measured confidence

Auditors who did none of the work judge random crops, with false claims planted. Overall is the lowest category.

Category Score, target 90
Identity 93.9
Vias 62.9
Blocks 61.5
Placement 55.6
Values 34.3
Layers 30.0
Copper 9.4
Connectivity 0.0

Photos alone cannot reach 90: values, layers and nets need measurements on the real board. Copper scores low mostly because a crop of smooth green mask cannot settle it, which needs a better audit.

Driver board run: every file from the test

Driver board run
    Driver run    
The full result of the Driver board test: the report, the evidence pictures, the KiCad copy and each routed stackup. Read it to judge the flow on a real board, including what it got wrong. You can open the board in KiCad and check any claim yourself.
Open the run

Process video: how it was made

Process video
    Process video    
The source of each scene in the video above, the full voice-over script and the tools that built it. It matters because nothing was filmed live, so this page says what each shot is. Use it to check a claim or re-cut a scene.
Open the video notes

Install and run

adom-wiki pkg install adom/ai-flow-reverse-engineering   # or ./build.sh from the source, which needs Rust
adom-wiki pkg install adom/service-kicad adom/adom-2dboard adom/adom-schematic

mkdir my-board && cd my-board
adom-aiflow-reverse init --photos ~/photos/my-board/ --rules kicad-default --ai-thread me   # every photo of the board, unsorted
adom-aiflow-reverse serve --port 8891 &   # the flow window: open this in a browser and leave it open
adom-aiflow-reverse next                  # always says what to do now: the exact command, or the input it needs from you
adom-aiflow-reverse auto --ai-thread me   # runs every program-only step, stops when it needs you or the run is complete
adom-aiflow-reverse video build           # the two minute video of the run; `auto` builds it after the report

init --photos takes a folder or a list of files and needs no face labels: close-up tiles, whole-board overviews and both faces can come in any order. The first prep sorts them and stitches one image per face (see "Photo intake" below). init --top a.jpg --bottom b.jpg still starts a run from one finished photo per face.

next walks the run and names the one next action. steps shows every stage and whether it is done, stale or next. An edit to an earlier artifact makes the later stages stale, and the flow window draws the loop back.

Running without a human: auto

auto runs every program-only step in order and ends with one line:

Line Exit Meaning
AUTO NEEDS AI: <input> 2 The AI's judgement is needed. The hints name the exact file or command: the scale, parts.json, the datasheet pins of each identified chip, blocks.json, what a failed check lists, the audit verdicts, report.md
AUTO COMPLETE: every step is done; video: <file> 0 Every step is done and the run video is built. When the video could not be built the line says the video was NOT built: <reason> and the exit is still 0: the video never holds a run up
AUTO FAILED: ... 1 A command failed, or the flow is not moving

A script alternates auto with the AI's inputs until it says COMPLETE. The last result is also in reverse-flow/auto.json, and every command's full output in reverse-flow/auto-log.txt.

The stages

Stage What happens Who decides
stitch (inside intake) Sorts an unlabelled set of photos into faces, close-up tiles and overviews, picks the top, and builds one mosaic per face at the close-ups' resolution, with a report of how well the tiles agree and what was not covered program (Python with OpenCV, called by the binary)
intake Finds the outline, straightens each photo, measures sharpness, plated holes and hole rows program
scale Pixels per mm from standard hole pitches, with one part body from a datasheet to pick the pitch standard; aligns bottom to top on shared holes program, AI names the body
parts Finds bodies, matches packages, then snaps each footprint's pads onto the metal in the photo program measures, AI reads markings
blocks Proposes groups of parts that sit together AI names them
copper Traces every island of copper on both faces into pours, tracks and vias program
mimic Writes the KiCad project with everything visible program
snapshot Saves the copy as it stands, before anything is inferred program
connect Lists the connections nobody can see and leaves them unrouted, each with its evidence tag; states the layer count from outside evidence, or UNKNOWN with its test and the minimum the photos give. connect route is optional program, AI adds datasheet nets and any outside evidence
review Scores every category 0 to 100 from measurements and random audits, and loops until the photo score reaches 90 or the loop stalls with a stated reason. The bench score is reported beside it program scores, an independent auditor judges the crops
tests One test for every INFERRED or UNKNOWN item program lists, AI writes the method
report The whole result with its evidence program

Each stage records its interactive PCB or schematic in the flow window, numbered and never overwritten, so the window replays the whole process afterwards.

Photo intake: any set of photos, no sorting by hand

A board usually arrives as several close-ups per face plus, often, one phone photo of each whole face. init --photos <folder or files> keeps them as they came (reverse-flow/photos-raw/), and stitch, which prep runs by itself on such a run, does the rest:

  1. Sorts. Every photo is matched against every other, with its EXIF rotation applied. Photos that match show the same face. Within a face, the photos with the finest pixels are close-up tiles and a photo more than 1.5 times coarser is an overview. Two overviews that do not match each other are two faces, so a row of holes that looks the same from both sides cannot join them.
  2. Picks the top: the face with the larger share of its board area under part bodies (areas that are neither the mask colour nor white print). stitch.json gives both shares and says when they are close; then look at both mosaics and, if the other face is the top, run stitch --top <name of a photo that shows the top>.
  3. Registers the tiles to each other at full resolution on the board surface. The solder mask colour is measured in each photo, so green, red and blue boards all work. One similarity per tile is solved for all tiles together, with one small camera correction per face (a radial term and a tilt) when it makes the tiles agree better. The overview only says where to look and steadies a tile whose matches sit in one corner.
  4. Builds the mosaic at the close-ups' own pixel size: each tile pixel is resampled once, nothing is sharpened, and the only tone change is a smooth gain per tile. Joins are moved by a graph cut to where two tiles look the same, which keeps them off parts. Where no tile covers the board the overview fills in and the area is recorded as low resolution; where nothing covers it the mosaic is black and recorded as not seen. A few millimetres of table stay round the board for prep.
  5. Reports in stitch.json: each photo's role, each tile's registration, how far the tiles disagree in their overlaps (median and 95th percentile, in pixels, on cells that were held out of the fit), coverage by source, and the evidence pictures: stitch/<face>-sources.jpg, stitch/<face>-seams.jpg with full-size crops of the joins, and stitch/<face>-overlap.jpg.

The mosaics become the run's photos (photos/top.jpg, photos/bottom.jpg), so prep, scale and every later step run on them unchanged.

The registration is Python with OpenCV, not Rust: tools/stitch.py, compiled into the binary, written to reverse-flow/stitch/stitch.py and run with python3 (set ADOM_REVERSE_PYTHON to choose another interpreter; it needs numpy and an OpenCV build with SIFT). The command line, the script's hash and its exit status go into the run ledger as a stitch event, and its output into stitch/stitch.log.

Thin sets are taken as they are. One close-up of a face is used as that face, with a note of every side on which the board runs out of the frame. Photos that match nothing are listed under unplaced and left out. Nothing is filled in that no photo shows. Two groups of photos that share nothing are taken as the two faces, and the report says that this is an assumption; with more groups than that, only the largest is built.

Red and blue boards stitch like green ones. prep itself looks for a green board; when it finds none it uses the board box recorded in stitch.json and says so. copper trace reads copper through a red or a blue mask (docs/method.md, "Whole faces of the red and the blue board"); tented vias are not read, and prep and detect still use green thresholds for holes and bodies. When no hole shows on both faces, give scale --flip x|y.

Two scores

One overall figure was always 0, because connectivity, the layer count and the values of unmarked parts cannot be earned from photos. There are now two, both computed from measurements and independent audits, with no formula changed:

Score What it covers Target
Photo score What photos can show: part identity and placement, values of marked parts, blocks, visible copper, vias, the joins a crop can show, the drawn layers against the photos 90, and the review loop works towards it
Bench score What needs the real board or outside documents: pins and connections no photo shows joined, the net of copper that reaches no pin, the layer count, values of unmarked parts Reported beside the photo score with what would raise it; nothing waits for it

The lower of the two is the lowest category, which is what the single figure was. docs/method.md, "Two scores", gives the membership of every ceiling.

The bench passback (optional)

After a run is complete, bench plan writes ordered instructions for a person with the real board and a multimeter: a continuity probe for every hidden connection, most settled first, each with a picture showing where both pads are, then the unmarked parts to measure and the layer count. bench ingest --file <results.json> records the answers as MEASURED, and the bench score moves by computation. docs/bench.md gives the results file format and a worked example.

The run video

Every run ends with a video of about two minutes (110 to 130 seconds), made by the program from the run folder alone. auto builds it after report; video build builds it by hand, on a finished run or on one still in progress (it then says which steps are not done).

reverse-flow/video/<project>-run.mp4          1920x1080, 30 fps, H.264 with AAC
reverse-flow/video/<project>-run.vtt, .srt    captions, never burned in
reverse-flow/video/<project>-run-poster.jpg   the title card
reverse-flow/video/video.json                 every scene: its times, the narration, the files it showed, and each figure with the file it was read from
reverse-flow/video/stills/                    the middle frame of every scene, and KiCad's own picture of the copy

The sequence is fixed and works on any board: the photos and how they were joined, the outline and scale, the parts (a box on each, the main chips close up), the functional blocks, the copper and vias over the photo with a zoom into the densest area, the KiCad copy wiped across the photo with its layer score, the nets by confidence and one or two nets lit, the schematic, both scores with what holds them down, and the tests and what is still unknown. A scene whose input is missing is left out, video.json says why, and the others are held longer so the total stays near two minutes.

  • Every figure is read at build time, from the run's files or computed by the program from them (both scores, the review's verdict, the hidden connections). Nothing is typed. If the review did not reach its target, the video says so.
  • The narration is filled from templates. The AI running the flow may add reverse-flow/video-notes.json: {"board": "one line naming the board", "chips": {"U1": "one line about this chip"}}. Those lines are spoken as written and video.json marks them as coming from that file. The house voice takes about five seconds for a fifteen word sentence, so the lines that must be said are short and the others are added by importance while the video stays under 125 seconds; video.json lists what was left out.
  • Rendering needs no browser: Python with numpy, Pillow and OpenCV draws the frames and pipes them to ffmpeg. The tool's source is in tools/video/ and is compiled into the binary. The voice is adom-tts say (en-US-AndrewNeural, default rate), one take per line; when it does not answer the video is built with captions only and video.json says so. KiCad's own picture of the copy needs KiCad's command line (ADOM_AIFLOW_KICAD_CLI); without it the scene shows the program's overlay.
  • A build takes one and a half to two and a half minutes on four cores (70 to 140 seconds measured on two boards). --no-voice skips the voice; --workers 1 uses fewer cores.

When the run sorted and joined its photos itself (init --photos), the photo scene shows the photos as they came (up to twelve), then each face with the close-up every area was taken from, the overlap figure and the coverage, all read from stitch.json. When photos given with --top and --bottom come from a stitcher's folder (a stitch.json beside them), init keeps that record and its source maps under reverse-flow/photos/stitch/ and the scene uses them the same way.

Rules are set at the start

init --rules takes a named profile or a JSON file. The same values drive the zones, the router and the gate, so nothing is checked against a rule it was not built to.

Profile Use
kicad-default KiCad's own defaults, which is what the shared KiCad service applies to a lone board
jlc-4l JLCPCB 4-layer capabilities. The gate needs a native kicad-cli, because the shared service does not read a project's rules

What it writes

kicad/<name>.kicad_pcb, .kicad_pro                  the copy
kicad/<name>.kicad_sch, <name>-<block>.kicad_sch    the schematic: root sheet (hierarchy, legend) and one sheet per block
kicad/RE.kicad_sym, sym-lib-table, fp-lib-table     the schematic's symbols, and the footprints the run was built from
reverse-flow/photos-raw/                            the photos given to `init --photos`, as they came
reverse-flow/stitch.json, stitch/                   `stitch`: roles, registration, overlap disagreement, coverage; mosaics, sources maps, seam crops, the script and its log
reverse-flow/parts.json blocks.json copper.json nets.json layers.json review.json tests.json
reverse-flow/report.md                              the result
reverse-flow/audits/<category>/                     audit samples, crops, contact sheets, verdicts
reverse-flow/confidence-scores.json                 every score with its inputs, for reading; nothing reads it back
reverse-flow/photo-layers.json                      `layers trace`: silk, pad shapes, holes and outline read from the photos; `build` draws them
reverse-flow/fidelity.json                          `check fidelity`: what KiCad draws against the photos, per layer, with what could not be scored
reverse-flow/unrouted.json                          the connections no photo shows, left unrouted, each with its evidence tag
reverse-flow/bench/                                 `bench plan`: plan.md, plan.json, crops/, results-template.json; `bench ingest`: measured.json, ingested/
reverse-flow/auto.json, auto-log.txt                how the last `auto` ended, and every command it ran with its output
reverse-flow/routes/L<n>/                           only after the optional `connect route`: one folder per stackup tried
reverse-flow/net-confidence.json                    `nets draw`: each net's level (its weakest link, with its place), pins seen and copper by rung
reverse-flow/nets/                                  `nets draw`, also run by `report`: confidence.jpg (both faces, copper by how well its net is proven),
                                                    confidence-top.jpg and -bottom.jpg at full size, attribution.jpg, confidence-table-<n>.jpg,
                                                    net/<name>.jpg per net, sections/ (ground, each rail, each bus, the rest), index.md, and
                                                    view.html (a net list beside the board, by confidence or by net; also a numbered view in the flow window)
reverse-flow/evidence/                              overlays to check every measurement by eye
reverse-flow/video/                                 `video build`, run by `auto` after the report: <project>-run.mp4, captions, poster, video.json, stills/
reverse-flow/photos/stitch/                         `init`: the stitcher's record and source maps, when the photos came with a stitch.json
reverse-flow/schematic/                             `report`: schematic.pdf and one picture per sheet, listed in the report tables
reverse-flow/views/                                 the recorded PCB and schematic views

The schematic

build (and schematic, which skips the board) draws the schematic from the run's own files, so it cannot disagree with the board: every symbol pin is a footprint pad number and every connection is a net of nets.json.

  • Sheets. A root sheet with the hierarchy and the legend, and one sheet per block of blocks.json: A4 when it fits, A3 at most, split when it does not. Each block is a frame with a centred uppercase title.
  • Symbols. Resistors, capacitors, inductors, diodes, LEDs, crystals, connectors, test points, switches and mounting holes take KiCad's standard shapes, fetched once and kept under reverse-flow/lib/sym. A library symbol is used only when its pin numbers are exactly the footprint's pads. An IC with no symbol is a box: by function when the run names its pins, by pad order otherwise.
  • Wires. Every pin of an IC or connector starts a strip: parts in series sit in line, parts to a rail hang from it, decoupling hangs at the supply pin it sits nearest on the board, and a net that goes elsewhere ends in a label on the end of its wire. Rails are power symbols.
  • Evidence. A solid wire leads to a pad seen joined to that net's copper in the photos; a dashed wire is inferred. A pin whose net is not known ends in a ? marker, never a no-connect flag. Each symbol carries hidden Evidence, Test and Marking fields.

What the AI may add, in parts.json and nets.json:

Field Meaning
part symbol "Library:Name" in KiCad's standard libraries, for an identified part. Refused, with a note, when its pins are not the footprint's pads
part pins pad number to pin name, or to {"name", "type"} (a KiCad pin type), from the datasheet. An IC becomes a box grouped by function; a transistor named G/S/D or B/C/E whose value says N or P, NPN or PNP gets its drawing on those pads
datasheets/<ref>.pins.json for each identified chip: the datasheet cited by name, revision and page, and every pad's name, type and optional expects (docs/method.md, "Datasheet pins"). datasheet apply writes it into the part's pins, attribution names the copper at those pins from it, and auto stops with AUTO NEEDS AI: datasheet pins until each identified chip has one or a reasoned {"available": false, "reason"}
connect witness (run by connect attribute) each pin of a chip with a pins file against the copper graph: agree, disagree or not visible, in detect/witness.json; disagreements as findings with a picture and a test under evidence/witness/; each net's datasheet witness in net-evidence.json, datasheetWitness in nets.json and net-confidence.json, and the Datasheet column of nets/index.md. It changes neither copper nor nets
connect pinout (run by auto before attribution) nets from the parts first: the chain identity, orientation, pinout per part in detect/pinout.json, and a net for every pin with a known function, by named rules (ground, pin function, datasheet tie, claimed part), tagged DATASHEET or INFERRED, never SEEN or MEASURED. auto asks once for the orientation of a chip that has a pinout and no settled pin 1. Header pads named on silkscreen: type them into the part's pins
part polarised true draws a capacitor with its polarity
net rail "supply", "ground" or "signal", when the name alone would mislead (a net is taken as a rail when it is called like one or feeds a supply input)
noConnect in nets.json pins a datasheet or the copper shows are unused: ["U1.5", {"pin": "U1.6", "why": "..."}]. Only these get a no-connect flag

check schematic passes when KiCad's ERC reports no error, the netlist KiCad exports equals nets.json pin by pin, and the sheet rules hold (labels on wires, right angles, titled blocks, no decoupling-only block, decoupling wired at its IC, no text under 40 mil or over a pin or body, nothing outside the border). It needs KiCad's command line: set ADOM_AIFLOW_KICAD_CLI to one that runs. The full report is reverse-flow/checks/schematic.json.

next and auto keep it current by themselves: in the connect step, after the nets are attributed and checked, auto runs schematic whenever parts.json, blocks.json, nets.json or net-evidence.json are newer than the sheets, then check schematic. A failed check stops auto with the list of what is wrong; a later edit to those files sends the flow back to it. report lists the sheets and writes reverse-flow/schematic/schematic.pdf and a picture of each sheet.

How the copper is read and what is left unrouted

docs/method.md explains the measurements and why each works. Read it before changing trace.rs, islands.rs or route.rs.

Contributing

Run cargo test --release before a change and look at evidence/copper-islands-*.jpg after one. Thresholds that came from measuring photos say so where they are defined; if you change one, measure it on more than one board. Tests in each module show the behaviour it must keep.

License

MIT. The timeline page in assets/ is copied from adom/adom-aiflow (MIT, Adom Industries). The label font atlases in assets/ are rendered from DejaVu Sans (Bitstream Vera licence) by tools/make_label_font.py.