Skip to content
View keivanmalhani's full-sized avatar

Block or report keivanmalhani

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Maximum 250 characters. Please don’t include any personal information such as legal names or email addresses. Markdown is supported. This note will only be visible to you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse
keivanmalhani/README.md

Hi, I'm Keivan

I build local-first tools for photographers and filmmakers. 24 of them are here, they all run entirely on your own machine, and none of them ask for an account.

The through-line: taking a shoot from memory card to finished post without a subscription and without uploading a client's work to somebody else's cloud. Along the way that turned into an agent safety story, a deployment story, and a few workshop tools built the same way.

PHOTO
  shutter-roll ....... scanned film gets its real stock, camera and shoot date back
  shutter-cull ....... burst clustering, blur and eye scoring, keepers picked
       |
       v
  Lightroom Classic reads the XMP sidecars natively

AGENTS
  shutter-mcp ........ the same library, read-only, exposed to AI agents
  shutter-cull-mcp ... the write side: agents propose, humans confirm, undo always

VIDEO
  shutter-select ..... local transcription, take detection, audio and image scoring
  shutter-clip ....... social re-rank, cut, phone-ready posts
       |
       +--> selects timeline, opens in Resolve or Premiere
       +--> analysis JSON, a versioned contract computed once

ON A SCHEDULE
  shutter-farm ....... the whole archive, nightly, in a container. Never twice.

WORKSHOP
  printcheck ......... drop an STL, see if it will print. Nothing uploads.
  spool .............. filament inventory and the true cost of a print, failures included
  gearwatch .......... is this used lens actually a deal, measured against its own sold history
  shutter-warehouse .. the other tools' output, aggregated three ways in Spark

BROWSER
  motion-recipes ..... fourteen micro-interactions with no animation library underneath
  portfolio-site ..... the site you are looking at, tested without a GPU
  d2-auth ............ The sign-in step for the Destiny tools. It is one page that nobody vis
  dps-maximizer ...... Sign in with Bungie, pick your class and what you are doing - a generi
  exif-atlas ......... is a sample report, so you can see what this produces without installi
  fireteam-report .... Compare a Destiny 2 fireteam's raid and dungeon clears and get a ranke
  gcode-lint ......... Static analysis for sliced 3D printer gcode. It reads the file once an
  goldenhour ......... A command line tool that tells a photographer when and where the light
  guardian-timeline .. Raid Report shows your clears. Destiny Tracker shows your kill to deat
  lutbox ............. Drop a photo and a `.cube` LUT onto the page. The grade is applied at 
  mcp-probe .......... Audit an MCP server before you connect an agent to it.
  timecode ........... SMPTE timecode arithmetic for video editors, with drop frame handled t
  weapon-report ...... light.gg tells you what is good. DIM tells you what you own. This tell

The tools

Project What it does Stack Suite
shutter-roll Scanned film comes home with no film stock, no camera, no ISO, and the scan date sitting w Python, exiftool, EXIF / XMP 31 tests
shutter-cull Point it at a shoot folder. It groups burst frames, scores every frame for blur, eye-openn Python, OpenCV, ONNX Runtime 127 tests
shutter-mcp An MCP server that lets Claude and other agents inspect a photo library conversationally: Python, MCP SDK, FastMCP 21 tests
shutter-cull-mcp The write side of the agent story. An agent cannot call a write tool here: it has to produ Python, MCP, agent safety 51 tests
shutter-select Culls raw footage. Transcribes every word locally with Whisper, finds takes by listening r Python, faster-whisper, PySceneDetect 97 tests
shutter-clip Zero-edit path from a footage drive to posted clips: motion-ranked picks with readable nam Python stdlib, ffmpeg, HEVC / VideoToolbox 53 tests
shutter-farm Point a container at a media volume and the whole archive gets culled on a schedule, witho Python stdlib, Docker, Kubernetes 92 tests
printcheck Drag an STL onto the page. Overhang faces glow red, thin walls amber, open edges cyan, and TypeScript, Three.js, Vite 28 tests
spool What a 3D print actually costs, which is never just the filament: the failed prints that b Python stdlib, Klipper / Moonraker, OctoPrint 370 tests
gearwatch Used camera gear pricing from the official eBay APIs, never a scraper. It builds a sold-pr Python stdlib, OAuth2, eBay Browse API 220 tests
shutter-warehouse Batch analytics over the data the other shutter-* tools produce. A PySpark DataFrame ETL, Python, PySpark, Spark SQL 17 tests
motion-recipes Fourteen production-ready micro-interactions on the Web Animations API, each with a live d TypeScript, Web Animations API, Vite 103 tests
portfolio-site The public site itself: a bilingual portfolio with a WebGL hero where photographs cross-di TypeScript, WebGL2, GLSL 68 tests
d2-auth The sign-in step for the Destiny tools. It is one page that nobody visits on purpose. TypeScript 37 tests
dps-maximizer Sign in with Bungie, pick your class and what you are doing - a generic mode or a specific TypeScript, @napi-rs/canvas, @types/node 1173 tests
exif-atlas is a sample report, so you can see what this produces without installing it. The library b Python 360 tests
fireteam-report Compare a Destiny 2 fireteam's raid and dungeon clears and get a ranked list of what to ru TypeScript, jsdom 390 tests
gcode-lint Static analysis for sliced 3D printer gcode. It reads the file once and tells you what is Python 258 tests
goldenhour A command line tool that tells a photographer when and where the light will be, at any coo Python 217 tests
guardian-timeline Raid Report shows your clears. Destiny Tracker shows your kill to death ratio. light.gg sh TypeScript 201 tests
lutbox Drop a photo and a .cube LUT onto the page. The grade is applied at full resolution, str TypeScript 253 tests
mcp-probe Audit an MCP server before you connect an agent to it. Python 221 tests
timecode SMPTE timecode arithmetic for video editors, with drop frame handled the way SMPTE ST 12-1 TypeScript 338 tests
weapon-report light.gg tells you what is good. DIM tells you what you own. This tells you what you actua TypeScript, @napi-rs/canvas, @types/node 306 tests

5032 tests across 24 repositories, and that number is generated rather than written: collect.py builds a clean environment per repo, runs each real suite, and writes the counts to verified.json. The portfolio page and this README are rendered from that file and refuse to print a count that did not come from a run. It exists because a README once claimed nine tests that were not there, and that is the cheapest thing in the world for an interviewer to check.

How I build

  • Local-first is a feature, not a limitation. Client work should not have to cross a network to be useful. Every engine reads from disk, computes on the CPU in front of it, and writes back beside the originals.
  • Deployable and private are not opposites. shutter-farm runs the same engines nightly in a container, mounting your volume, on your cluster, with no outbound network.
  • Judgment beats thresholds. Scores are percentile-ranked within a run, so each shoot is judged against itself instead of against a constant that breaks on the next one.
  • Agents propose, humans confirm. The write-capable MCP server cannot be talked into a write: it needs a content-addressed plan token, an exact-phrase confirmation, and a staleness re-check at write time. Everything is undoable.
  • Composition over coupling. Tools call each other's CLIs and read versioned JSON rather than importing each other, so the expensive analysis runs once and either side can move.

Every repo is MIT, has CI, and reads in English and Spanish.

Currently looking for customer-facing technical work where the job is turning a hard system into something a person can actually use.

Popular repositories Loading

  1. shutter-cull shutter-cull Public

    Local-first AI photo culling: burst clustering, blur/eye/aesthetic scoring, XMP writeback for Lightroom

    Python

  2. shutter-select shutter-select Public

    Local-first AI video culling: Whisper transcription, take detection, quality scoring, OTIO/FCPXML selects timelines

    Python

  3. gearwatch gearwatch Public

    Used camera gear price tracking from the official eBay APIs. Sold-price distributions per model, no scraping anywhere in the codebase

    Python

  4. motion-recipes motion-recipes Public

    Fourteen production-ready micro-interactions on the Web Animations API, with zero runtime dependencies

    TypeScript

  5. portfolio portfolio Public

    Photography and software portfolio: WebGL hero, bilingual, zero backend, under 40 KB gzipped

    TypeScript

  6. printcheck printcheck Public

    Drag an STL into the browser and see overhangs, thin walls, bed fit and the best print orientation. Nothing uploads

    TypeScript