michele 39169b33b8 Note live Emmaforo PCB exam wall times (parse, Z0, checks, AI).
Read-only docker exec on stored pcb.kicad_pcb. No pipeline change, no deploy.
2026-09-20 21:27:27 +02:00
2026-07-16 21:29:45 -07:00

Periscope (DeepSeek)

Periscope reviews schematics the way a good senior engineer does: with the datasheets open.

This tree is adapted from manvalan/pinscope so the pipeline talks to the DeepSeek API (deepseek-flash, with legacy aliases still accepted). Do not use Anthropic.

Give it a netlist, a BOM, and your datasheet PDFs. It builds a graph of your design, reads each IC's datasheet, and checks the circuit around every part against what the manufacturer actually specifies — reference application, pin functions, absolute maximums, recommended operating conditions. Every finding points at the datasheet page that backs it up.

What changed for DeepSeek

DeepSeek's Chat Completions API is OpenAI-compatible but does not accept native PDF documents. Periscope therefore:

  1. Extracts datasheet text with pypdf (page-marked) and sends it as chat content.
  2. Renders pages to JPEG with PyMuPDF when the stage uses a vision model, so pin diagrams and tables survive.
  3. Runs extraction skills locally. skills/*/SKILL.md is inlined as the system prompt; validate.py runs in-process. You do not need Anthropic Console Skills.
  4. Round-trips reasoning_content when DeepSeek thinking mode is on, so multi-turn review and tool calls do not 400.

Default routing:

Stage Model
Pintable / pattern / specs extraction deepseek-flash (native vision)
Per-IC datasheet review deepseek-flash
Auto-resolve / normalize deepseek-flash

Override with PROVIDER_* and MODEL_*_DEEPSEEK in .env. See periscope/src/backend/.env.example.

Layout

  • periscope/src/ — native Periscope
  • periscope/dependency/ — inherited PinScope (AGPL in-tree dependency; do not delete)
  • LICENSE — GNU AGPL v3 (visible at repo root)
  • vendor/impedancefinder/ — third party (license UNKNOWN)

See periscope/README.md and periscope/src/docs/development/PINSCOPE_INDEPENDENCE_PLAN.md.

How it works

Pipeline: the netlist and BOM are parsed into a design graph; datasheet PDFs are extracted into pin tables and specs; a per-IC review reads both and files findings cited to datasheet pages; the derating table and BOM roll-up are computed straight from the graph, no model involved.

  1. Parse the BOM (CSV/XLSX) and netlist (PADS-PCB .asc or EDIF 2.0.0 .edn) into a queryable bipartite graph of components and nets.
  2. Extract pin tables and specs from the PDFs. Large datasheets are trimmed to the relevant pages first, and every extraction is cached in a shared library.
  3. Review each IC in isolation. The model gets the datasheet plus that IC's circuit neighborhood, can query the graph, and files findings with severity, reasoning, and page citations. Extraction now also stores absolute-maximum ratings so the reviewer does not have to rediscover supply limits from a 300-page PDF.
  4. Compute the deterministic parts deterministically — BOM roll-up and a capacitor voltage-derating table come straight from the graph.

Try it on the bundled design

periscope/dependency/simple_project/ is a small MSPM0G3507 board with a CH340E USB-UART bridge and an SPX3819 LDO.

You need Python 3.12+, Node 20+, and a DeepSeek API key:

python3 -m venv .venv
source .venv/bin/activate
pip install -r periscope/src/backend/requirements.txt
cp periscope/src/backend/.env.example .env   # set DEEPSEEK_API_KEY

python3 -m uvicorn backend.main:app --reload --host 127.0.0.1 --port 18741

# in another terminal
cd periscope/src/frontend && npm install
NEXT_PUBLIC_API_URL=http://127.0.0.1:18741 npm run dev -- --port 18742 --hostname 127.0.0.1

Open the frontend URL, create a project, and feed it the netlist and BOM from periscope/dependency/simple_project/. Datasheets are fetched automatically (LCSC, TI, optional DigiKey); you can still drop in PDFs by hand. Fetched PDFs and extracted pin tables land in the Library (sidebar) and are reused on later projects. Everything runs locally against your own DeepSeek key; projects and the extraction library live in data/. Skills are local periscope/src/skills/*/SKILL.md — do not run scripts/upload_skills.py.

Docker

cp periscope/src/backend/.env.example .env   # set DEEPSEEK_API_KEY
docker compose up --build

Backend on port 8080, frontend on port 3000.

Update a live instance (e.g. periscope.michelebigi.it)

One checkout on the VPS: /root/periscope. The GitHub clone URL may still be manvalan/pinscope; clone into that path so the folder is not pinscope:

git clone git@github.com:manvalan/pinscope.git /root/periscope

Do not keep a second live tree under /root/pinscope (or /opt/pinscope). Stop compose there, then deploy only from the canonical root:

cd /root/periscope
./scripts/update-periscope.sh

The script cds via dirname "$0"/.. (no find). It refuses to run if the resolved root is not /root/periscope. Compose project name is periscope. After up, the script connects periscope-frontend / periscope-backend to Docker network pinscope_pinscope (where railway-caddy reverse_proxies periscope-frontend:3000). It pulls the current branch, writes NEXT_PUBLIC_API_URL / CORS_ORIGINS for https://periscope.michelebigi.it, rebuilds both Docker images, and leaves data/ alone. First run: put DEEPSEEK_API_KEY in .env at the repo root (compose reads that file). --no-pull skips git. SITE=https://other.host ./scripts/update-periscope.sh overrides the public URL.

Do not set ENVIRONMENT=production unless Clerk auth is configured — that flag refuses to boot with auth disabled.

License

AGPL-3.0 (see LICENSE). This tree is derived from Faradworks/Pinscope. Faradworks does not operate this instance. For a commercial license of upstream Pinscope, write to Faradworks as they publish it (dev@faradworks.com historically). For this Periscope instance, contact the operator (Michele Bigi, mikbigi@gmail.com).

S
Description
No description provided
Readme AGPL-3.0
8.2 MiB
Languages
Python 68.1%
TypeScript 31.3%
CSS 0.3%
Shell 0.2%
JavaScript 0.1%