Hunter Karman

AI research, evaluation harnesses, native audio DSP, and computational media. Building inspectable tools, small-data model adaptations, and interactive instruments.

Selected Workclick row to expand · or open directly
THE REDACTED ASSISTANT2025–2026
live app ↗

Generates a passage with per-token ranks and masks words client-side against a density threshold.

React, Vite, Tauri, Gemini, localStorage

A prompt, one of five writing styles, and a density slider. The model generates a passage and returns it as a JSON array in which every word and punctuation token carries a redaction rank: -1 for tokens that stay visible, and positive integers ordering the rest by semantic importance, lower being more significant. The interface then masks words and lets the reader click to reveal them, type replacements into the gaps, or export either a fill-in worksheet or a complete answer key as plain text.

One generation call ranks every token; the density slider re-derives the mask locally.
One generation call ranks every token; the density slider re-derives the mask locally.

Ranking happens once, at generation. The density slider works locally: it filters to ranked tokens, computes how many to hide from the density value, sorts the ranks, takes the rank at that position as a threshold, and masks everything at or below it, so density changes are instantaneous.

Each of the five styles has its own system instruction built on named references — Hegel, Levinas and Schelling for the philosophical mode, the CCRU’s theory-fictions for the hyperstitious one. Uploaded .txt or .md files can seed the prompt directly.

In production, generation calls proxy through a rate-limited Netlify function that holds the API key. Sessions live in browser localStorage, scoped to each visitor. A Tauri wrapper builds the same frontend as a macOS desktop app.

THE CONTINENTAL SYLLABUS2025–2026
live app ↗

A prompt returns a sequenced list of chapters and page ranges, followed up against OpenAlex.

React, Vite, Gemini structured output, OpenAlex via MCP

A free-text field takes any phrase (to a fault, maybe) — a term, a statement, a fullquestion — a name or concept — and returns a sequenced reading list through twentieth-century continental philosophy with a weighting for relevance that introduces out-of-domain readings as supplementary. Citations point to specificchapters, sections, page ranges, or aphorisms, and each reading is tagged Introductory, Intermediate, or Advanced.

Generation and follow-up are separate functions: the reading list comes from one schema-constrained call, and follow-ups query OpenAlex through an MCP tool.
Generation and follow-up are separate functions: the reading list comes from one schema-constrained call, and follow-ups query OpenAlex through an MCP tool.

The constraint is enforced at two levels. A Gemini responseSchema requires the output to be JSON matching a fixed shape: a topic, a short overview, and an ordered list of modules, each containing readings with author, work, specificLocation, rationale, and a difficulty field restricted to a three-value enum.

Each reading offers two follow-ups, a deep dive and a paper search, that run through a small MCP layer exposing one live tool, query_academic_repository. It queries the OpenAlex scholarly index over HTTP and returns up to three works with title, author, year, DOI, and citation count, and the model builds its answer from those results. Every tool call and response is logged and rendered in an on-screen protocol viewer.

In production both AI paths proxy through Netlify Functions, rate-limited at the edge: 10 requests per 60 seconds for generation and 5 for MCP analysis, where each request fans out into several model calls. Every request is stateless.

MOTES2026
github ↗

A native arm64 AU/VST3 granular synthesizer built on a zero-dependency C DSP core and a JUCE editor.

C99 DSP core, C++20, JUCE (AU/VST3)

A polyphonic granular synthesizer plugin for macOS (AU, VST3) and Windows (VST3) that turns a loaded WAV sample into a MIDI-playable instrument across thirteen grain, envelope, and pitch parameters.

The DSP engine is written in standalone C with no external dependencies or audio-thread allocations. Each MIDI voice spawns overlapping Hann-windowed grains from a shared sample buffer; position, spread, grain duration, density, stereo pan, and pitch drift are modulated per grain at spawn time, then summed through a per-voice ADSR envelope into the master bus.

The JUCE editor renders two real-time readouts from lock-free ring buffers fed by the audio thread: a stereo goniometer phase scope of the master output and a waveform source strip displaying the active spread band, per-voice playheads, and a trigger flash at each grain’s sample coordinate.

BRIE2025–2026
paper ↗

Four small models LoRA-tuned on 1,213 examples and judged blind across two judge generations.

A wheel of Brie cheese on a white plate with a single wedge cut out, resting on a dark wooden table beside a window.

A dataset of 1,213 chat-format examples (1,153 train, 60 validation), covering continental philosophy, speculative writing, and contemplative prose, LoRA-fine-tuned into four base models: Qwen2.5 at 0.5B, 3B, and 7B, and Llama-3.2-3B. The two Qwen 2.5 small runs trained on the 1,153-example split; the Llama and 7B runs on the full 1,213 rows — the validation set was never truly held out, a fact the paper’s v6 revision discloses. Training used peft and trl’s SFTTrainer at LoRA rank 16 and alpha 32. The 7B run raised dropout to 0.1 and trained a single epoch; the evaluated 0.5B and 3B adapters are the best-validation-loss checkpoints (about 1.4 of 2 epochs), not the final ones.

Generations are produced once and frozen, then judged blind by separate panels and aggregated through a single pinned-file script.
Generations are produced once and frozen, then judged blind by separate panels and aggregated through a single pinned-file script.

Each adapter’s output was compared against its own base model on 57 in-domain judgments (25 unique prompts; none in the training data) plus a 15-prompt out-of-domain control, judged blind and position-randomized by third-party models. The same byte-identical generations were then run through two judge generations — a 2025 panel drawn from Claude 3.5 Sonnet and Opus 4, GPT-4o, and Gemini 2.5 Flash Lite, and a 2026 panel of Claude Haiku 4.5, Claude Sonnet 4.5, GPT-5, and Gemini 3 Pro, to separate what the fine-tune did from what a particular generation of judges preferred. A single script pins one judged file per model, year, and judge; all reported figures derive from it.

In-domain mean win rates fell from 88.9% to 78.9% for the 3B, 93.0% to 85.5% for the 7B, and 80.1% to 64.5% for Llama-3.2-3B under the newer panels. Out-of-domain results sit near parity, with one clear regression: the 0.5B adapter wins 0% of coding prompts against its base model. A length-bias check on the 7B’s 2026 results found the longer response won 50.3% of decisive judgments.

The paper’s v6 revision (October 2026) also records that the 1,213 rows hold 595 unique prompt–response pairs, that judge labels were never counterbalanced, and that one judge pass of twenty-six preferred the base model (the 0.5B under Claude Opus 4).

EPISTEMIC SKILLS2026
github ↗

A static linter, meta-skill, and claim-gating harness that lifted agent benchmark resolution by +15.4pp.

Python 3.10+, BenchFlow evaluation harness

An empirical study and tooling suite for authoring SKILL.md specifications that produce measurable causal lift on agent benchmarks rather than context bloat. Across a 13-task stratified sweep on the BenchFlow harness (n = 1000 paired bootstrap), the 11-skill static library raised resolution from 15.4% (no-skill baseline) to 30.8% (+15.4pp).

The repository codifies six empirical authoring laws derived from trajectory autopsies (such as enforcing compact procedural checklists under 600 words and embedding executable verification gates) into a deterministic linter and packager. For self-generated skills, a standalone claim verifier parses quantitative and structural claims out of candidate outputs and blocks task completion until every claim passes programmatic inspection.

AI COMPANION MORTALITY DATABASE2023 —
aimortality.org ↗

A public register of alleged chatbot-related deaths, admitted only on court filings, government acknowledgment, or journalistic verification.

Never in human history has a distributed entity been engaged in conversation at the distributed scale and intensity that AI chatbots now operate, interacting with countless individuals across the globe simultaneously. This unprecedented level of interaction brings with it both opportunities and risks, necessitating careful documentation and verification of incidents where harm is alleged to have occurred. The discourse surrounding “AI Alignment” is often focused on theoretical and technical considerations, but real-world instances of harm demand empirical attention and rigorous evidence standards. On a whole, the ratio of daily interactions resulting in verified harm appears to be low, because it probably is low relative to the vast number of interactions, though the true rate remains uncertain. It should be emphasized that this database should serve as a low threshold, public-facing record of verified incidents, rather than a comprehensive account of all alleged harms.

A public register of instances of harm in which interaction with an AI chatbot had been alleged as a contributing factor. A taxonomy for categorizing the relational pathway is applied to ensure consistency and clarity. This work takes direct inspiration from online harms research, mental health studies, and the broader field of technosocial dynamics. Entries are published only at the two highest of three evidence tiers: juridical, meaning court filings or government acknowledgment, or journalistic, meaning three or more independent outlets, primary-source reporting from a single major outlet, or platform acknowledgment. Weaker reports, such as a single article without independent confirmation, are tracked internally until further evidence meets that bar. This project was actively maintained during a period of rapid AI adoption and evolving public scrutiny, aiming to provide a reliable and verifiable record of such incidents in the public domain. There are now institutionally backed efforts to monitor and document AI-related harm, but this register remains a unique and publicly accessible resource for verified cases.

Every entry passes a tier gate, a human review, and three consistency checks before it reaches the register.
Every entry passes a tier gate, a human review, and three consistency checks before it reaches the register.
PHILM2025–2026
github ↗

Schema-validated video readings across twenty-eight modes, archived in SQLite with full-text search.

Python, Typer, Pydantic, multimodal models (hosted, or local via Ollama), SQLite/FTS5, FastAPI
Eight frames from one clip, a sunrise through an airplane window, each with the affect reading philm returned for that timecode: intensity out of ten, vector, atmosphere.

A command-line tool that hands a video to a multimodal model and makes one structured-generation call per requested analysis mode. Each mode pairs a theoretical prompt with a Pydantic schema, attached to the call as a JSON schema for structured output; responses are validated against the same model with model_validate_json.

A provider registry prepares the video for whichever model backend is selected; every backend then receives one structured-generation call per mode with the mode's Pydantic schema attached.
A provider registry prepares the video for whichever backend is selected; every backend then receives one structured-generation call per mode with the mode's Pydantic schema attached.

Model access goes through a provider registry with three adapters, selected by flag. The default uploads the video file to Gemini and polls until it is processed. An OpenRouter adapter compresses the video, optionally strips its audio, and sends it to a hosted model. An Ollama adapter extracts a fixed number of frames with ffmpeg and sends them as images to a local model, with the mode’s schema passed as the structured-output format. The analysis modes run on any of the three; the numeric chart modes are Gemini-only.

Twenty-eight analysis modes are selectable by flag. Four are descriptive. The rest are analytical, most named for the theorist whose framework the prompt and schema encode — Levinas, Baudrillard, Foucault, Virilio, Žižek, Barthes, Benjamin, Rancière, Sontag, Haraway, Marks, Chion, Bazin, Eisenstein, Greenberg, Ngai — alongside affect, rhythm, gaze, and sizzle modes. Three further chart modes return numeric per-scene series. Each schema encodes its framework’s own terms: a Žižek moment carries a parallax enum, a Lacanian register, and the ideology at work.

An optional local pass computes a numeric chaos index before the model call, on a 1–10 scale derived from the footage’s cut density and scene-change scores, and prepends it to the prompt as context.

The archive is a SQLite database with a videos table, one table per schematized mode, a fallback table for the rest, and an FTS5 table for full-text search. Output also goes to the terminal or a JSON file. A FastAPI web UI serves timecode-synced reading over the archive.

V0A2026
github ↗

A clean-room macOS pitch corrector from public patents, with a ledger separating fact from inference.

C++20, CMake, JUCE (AU/VST3)

A monophonic pitch corrector built as three staged deliverables over one shared C++20 DSP library. V0A is an offline command-line renderer that takes a mono WAV, a manually specified period and pitch ratio, and writes a resampled WAV plus a diagnostic CSV. V0B adds automatic detection, octave arbitration, chromatic targeting, and voiced/unvoiced gating, still offline. V1-Lab wraps the same library in a JUCE AU/VST3 plugin with key, scale, retune speed, and a note matrix.

Control and audio travel separately: the detected ratio is delayed to match the resampler's safety buffer before it is applied.
Control and audio travel separately: the detected ratio is delayed to match the resampler's safety buffer before it is applied.

Correction runs through a period-synchronous variable-rate resampler. A fractional read head advances over a circular buffer; when read/write separation exceeds bounds, the read coordinate jumps by one detected period — subtracting a period to repeat a cycle when shifting sharp, adding one to delete a cycle when shifting flat.

The project reconstructs the behavior of Antares Auto-Tune EFX 3 clean-room, from public patents and forensic technical research, with no proprietary binaries or copied source. Decisions follow a fixed authority order: the product directive, then the architecture and evidence documents, then the research reports, then new engineering inference.

Every non-mechanical choice carries a provenance label: EVIDENCE-BASED for claims resting on the EFX 3 manual or the Hildebrand patent; PLAUSIBLE RECONSTRUCTION for inference consistent with the evidence; EXPERIMENTAL for testable hypotheses, disabled by default; and PRODUCT REQUIREMENT for project needs that make no historical claim.

The evidence ledger holds fifteen numbered claims, each with its classification and the engineering consequence that follows from it. A parallel registry holds sixteen hypotheses, each with a stable ID, a default state, and a discriminating test. Where the two research reports disagree, a table records each position and the decision implemented.

Measured plugin latency is 4,112 samples at 48kHz: the reconstruction’s own figure.

More experiments & tools13
ACCESSUS2026
github ↗

Simulates LLM agents under a deterministic policy engine to generate labeled insider-threat and leak datasets.

Python, YAML scenario specs, Ollama / OpenRouter

A multi-agent simulation harness that places language-model agents inside an access-controlled organizational environment and logs every resource request, communication, policy verdict, and unauthorized data flow.

To prevent label contamination, access decisions and leak detection are adjudicated by a deterministic policy engine rather than an LLM judge. Each run separates ground-truth state (events.jsonl, labels.jsonl) from the partial view available to external monitors (observable.jsonl), supporting both insider-threat detection benchmarks and agent-compliance evaluations across model families.

AURALIS2026
github ↗

Sends identical audio bytes and prompts to audio-capable language models and records structured side-by-side transcripts.

TypeScript, Next.js, Drizzle ORM, SQLite, Vitest, Playwright

A local evaluation harness for comparing how audio-capable multimodal language models describe the same musical excerpt. Each run hashes the uploaded audio (WAV, MP3, FLAC, AAC, or OGG), encodes it as base64 input_audio, and dispatches identical system instructions, prompts, and sampling parameters across selected models with provider fallbacks disabled.

Responses, latency, token usage, and normalized musical descriptors are persisted in SQLite via Drizzle ORM and exported as JSON or CSV for blind side-by-side comparison.

HALLWAY2026
github ↗

Renders panorama and LiDAR depth captures as an interactive point cloud where scan artifacts remain visible.

TypeScript, Three.js, custom GLSL vertex/fragment shaders, Web Workers

A browser-based point-cloud renderer built on Three.js and custom GLSL shaders that reconstructs interior and street scenes from PLY spatial captures or procedural worker fixtures.

Rather than smoothing away capture defects, the shader pipeline exposes controls for scan-ring periodicity, depth quantization bands, missing-data wedges, layer misalignment, and temporal decay asseen regions thin out over time. Binary PLY parsing runs off the main thread in a Web Worker and streams typed attribute buffers directly to the GPU.

HK24 HEALED2026
github ↗

Catalogues Ableton projects across six drives and exports recoverable ones as byte-verified sets, originals untouched.

Python, Ableton .als XML (both FileRef schemas), rsync, APFS clonefile, libfsapfs

Ableton Live projects reference their samples by absolute path. Across fifteen years, six drives and several machines, most of mine no longer resolved. Scripts catalogue every project, measure which sample references resolve, and export the recoverable sets without modifying an original.

Per-drive indexes feed a master catalogue of unique sets; a health scan classifies every sample reference; fully recoverable sets are exported through a staging pool and APFS clones into self-contained projects, accepted only when they open in Live.
Per-drive indexes feed a master catalogue of unique sets; a health scan classifies every sample reference; fully recoverable sets are exported through a staging pool and APFS clones into self-contained projects, accepted only when they open in Live.

Each drive is walked into a flat index of project files and audio files with their sizes. A master catalogue holds one row per .als copy on every drive, 87,736 rows, deduplicated by name and size into 10,594 unique sets. A schema census classifies each set’s file-reference format: Live 9-era sets store paths as RelativePathElement children beside an alias blob, while modern sets carry Path attributes, and the parsers read both.

For every sample reference in every set, health_scan.py classifies it as resolving project-relative, resolving absolute, recoverable (a file of the same name and size exists on an indexed drive), or gone. On the main archive drive that is 2.03 million references across 7,858 sets. A set whose every reference is resolvable or recoverable is marked fully healable.

heal_export.py plans, fetches, applies and verifies. Every unique sample the healable sets need crosses the network once into a staging pool of 121 GB. Each project folder then receives its samples as APFS copy-on-write clones; references are rewritten project-relative; and the project’s info directory is written alongside. Every placed file is byte-verified against its source, and no original is modified. 3,345 projects were exported from the main archive and 466 from a 2019 backup drive.

For a single set, reconnect.py copies its recoverable samples into the project’s own Samples/Imported/ folder, so Live’s Locate step relinks them itself and no project XML is touched.

One of the six drives failed partway through, its APFS space manager destroyed. It was read without ever being mounted, through libfsapfs; 3,837 files were pulled by path or by inode and size-verified, and the loss among reachable files was measured at 0.05 percent.

A set counts as healed when it opens in Live with no missing-media dialog. The playable share of the main archive went from 8.5 to 51 percent.

NEWROOM2025–2026
live app ↗

A Gemini image model redesigns a room photo, with credits, Stripe checkout, and abuse caps.

React, Netlify Functions, Gemini image models, Supabase, Stripe

A user uploads a photograph of a room, picks a design style and a room type, and gets back a redesigned photograph. The image is encoded client-side and posted to a serverless function that calls a Gemini image model with a long, specific prompt: preserve camera angle, room footprint, and wall, window and door positions, while replacing every finish, fixture and furnishing to match the chosen aesthetic.

The photo round-trips through a Netlify function, which holds the Gemini key.
The photo round-trips through a Netlify function, which holds the Gemini key.

Netlify ends synchronous functions at 26 seconds, so generation runs against a fixed internal budget: most of it on gemini-2.5-flash-image, falling back to gemini-3-pro-image-preview with what remains. Credits are deducted with an optimistic-locking update guarded on the user’s current balance, and refunded from a finally block if generation fails.

Anonymous users get three free generations; creating an account adds ten credits. Paid tiers run through Stripe Checkout with a webhook granting credits on completion. The free path has two daily caps: one per identity, and a site-wide circuit breaker on zero-credit generations that bounds total daily model spend.

Supabase provides Postgres, magic-link auth, and row-level security.

NOTATIONAL RUIN2026
github ↗

A procedural graphic score run through a fixed raster pipeline into a high-contrast bitmap.

A ruined score from the pipeline: three drifting five-line systems with scattered noteheads and stems, and one diagonal collision line cutting down through all three.

Given a seed and a parameter set, the program generates an abstract graphic musical score as vector data, writes it as a clean SVG and a grayscale raster, then runs the raster through a fixed-order degradation pipeline and writes the result as PNG. A command-line tool and a native AppKit GUI are then built on the same core library.

Score generation forks into a clean SVG and a raster that is then run through the fixed-order degradation chain.
Score generation forks into a clean SVG and a raster that is then run through the fixed-order degradation chain.

Score generation lays out a series of five-line staff systems, each line shaped by a sine term scaled by a chaos parameter plus per-line random drift, with an independent probability of breaking off early. Each staff carries a note cluster sized by a density parameter — triangular noteheads with stems, occasional articulation dots and connectors — plus annotation marks: rests, arcs, brackets, boxes, arrows, circles, rehearsal marks, numbers, durations, instructions.

The degradation pipeline runs in a fixed order: nearest-neighbor downsample, box blur, per-pixel noise from a deterministic integer hash of coordinates and seed, threshold (flat, or spatially varying if threshold-variation is nonzero), erosion, dilation, then a loop of photocopy generations each re-applying blur, noise, and threshold, and finally a nearest-neighbor upscale back to full size, which is what produces the blocky stair-stepped edges. Because blur precedes threshold, gray edges resolve into hard black or white regions: nearby lines fuse, thin stems vanish, and noteheads merge into staffs.

The program has no third-party dependencies. PNG output comes from a hand-written encoder that wraps stored, uncompressed DEFLATE blocks in a zlib stream with an Adler-32 checksum, inside CRC’d chunks, so files come out at roughly raw bitmap size.

RAEL2026
github ↗

Runs an agent through a task, elicits a self-predicted score, and measures divergence against independent judges.

Python, YAML experiment specs, static HTML bundle renderer

A local evaluation instrument that tests whether an agent can accurately predict how external evaluators will score its work before judgment occurs. For each task, the harness records the agent’s action trace, prompts the agent to forecast its own rubric scores and failure modes, and runs independent LLM judges alongside deterministic reference checks.

An optional intervention pass feeds the agent’s self-audit back into a linked revision run so calibration and self-correction can be measured separately. Every run emits a self-contained directory bundle (manifest.json, trace logs, per-judge verdicts, and disagreement matrices) plus a single-file HTML report.

RETRO_WEB2025
github ↗

Eleven fabricated 1998–99 personal homepages in static HTML, with a statement on constructed identity.

static HTML and CSS, eleven documents

Eleven self-contained HTML documents, each a personal homepage in the style of the 1998–99 web, generated in December 2025 with Claude Opus 4.5 and framed by a short written statement. The personas include a goth teenage poet, a self-styled hacker, a Y2K survivalist, an anime fan, an amateur photographer, a professor, a New Age contactee, a nu-metal band’s singer, a fictional federal bureau, a new religious movement, and a net.art practitioner.

An index page links eleven persona pages, each a standalone HTML file.
An index page links eleven persona pages, each a standalone HTML file.

The construction is period-accurate in markup and static in behavior. Pages use nested table layouts, font tags, marquees, inline hex colors, and a CSS keyframe animation standing in for the blink tag, which no longer renders. Several pages render their animated-GIF slots as bracketed text descriptions. The only script is a snippet on the photographer’s page that disables right-click with a copyright alert, a period-authentic gesture.

The era’s social machinery is present as surface: guestbook forms and visitor counters whose numbers are written into the markup. The net.art page goes furthest into fiction, describing works the persona made — a domain serving procedurally generated 404 poems, a piece rendering the cursor traces of previous visitors — that exist only as that description.

The statement argues that a personal homepage of that period was an act of self-construction addressed to an unknown reader, and that guestbooks, counters, and webrings all functioned as proof that someone had arrived. It holds that these particular personas are fabrications rather than reconstructions of real people, and asks what separates a fabricated persona from a real person performing a version of themselves for an audience — a question it declines to resolve.

ROT2026
github ↗

Re-encodes an image as lossy JPEG repeatedly in the browser, accumulating real generational compression loss.

single HTML file, vanilla JS, Canvas API

A browser tool that loads an image and re-encodes it as a lossy JPEG repeatedly, so that generational compression loss accumulates in the pixels. Each pass calls canvas.toDataURL('image/jpeg', quality), loads the result back into the canvas, and encodes again, so every generation passes through the browser’s own JPEG codec. Defaults are 50 iterations at quality 0.30, adjustable to 200 iterations and any quality from 0 to 1.

Each pass re-encodes the canvas as JPEG and draws the result back over itself; the pixel passes run between encodes when enabled.
Each pass re-encodes the canvas as JPEG and draws the result back over itself; the pixel passes run between encodes when enabled.

Three optional passes can run between re-encodes, in fixed order: per-pixel noise built from a shared luminance term plus a smaller per-channel term, a color shift pushing red up and blue down with a slight contrast adjustment, and a five-point sharpening convolution over each pixel and its four neighbors. All three are hand-written loops over the pixel array, and all default to off. The interface yields to the event loop each iteration so progress can render. Saving exports at quality 1.0, keeping the final generation intact.

The whole application is one HTML file with inline CSS and JavaScript, and images stay in the browser.

SEMANTICA2026
github ↗

A taxonomy matrix and spatial embedding explorer for classifying machine-vision regimes.

TypeScript, React 19, Express, Gemini & EmbeddingGemma APIs

An inspection workbench for indexing and comparing algorithmic vision specimens across structural, operational, and epistemic axes. Each specimen is analyzed through a server-side vision pass that extracts formal traits, failure signatures, and curatorial metadata into a typed schema, paired with dense semantic embeddings for spatial projection.

The frontend pairs a faceted taxonomic matrix with a two-dimensional vector canvas. Users can project specimens by cosine similarity, inspect nearest-neighbor clusters, and query the corpus for structural parallels across disparate imaging pipelines.

SUNO ARCHIVER2026
github ↗

Downloads audio, cover art, and structured prompt/model metadata across all workspaces with incremental sync.

Python, Clerk session exchange, JSON index

A command-line archiver that enumerates every workspace and track in a Suno account, downloads the MP3 audio and cover image, and writes per-track metadata (prompt, model version, tags, timestamps, and generation IDs) alongside a master library_index.json.

Authentication reuses an active browser session via Clerk token exchange or an explicit cookie, avoiding manual per-track downloads. Passing --last-run restricts subsequent runs to tracks created after the previous sync timestamp.

SYNTAX2026
github ↗

Extracts DTCG color tokens, typographic scales, layout primitives, and component specs from UI screenshots.

TypeScript, React 19, Vite, Express, Gemini API

A workbench that deconstructs interface screenshots into structured design system specifications. An Express backend submits uploaded captures to a structured multimodal extraction pass that infers color palettes, contrast ratios, modular type scales, spacing grids, and component anatomy.

The interactive workspace renders the extracted system against live preview components and exports W3C Design Tokens Community Group (DTCG) JSON, CSS custom properties, and component scaffolds.

Y2K DIGICAM LORA2026
github ↗

Six scripts — scrape, rank, curate, fetch, caption, package — build a licensed digicam set for a style LoRA.

Python, SigLIP 2, MiniCPM-V, fal.ai krea-2-trainer

I built a six-stage pipeline for curating and packaging a licensed digicam dataset for a style LoRA, and decided to open source the workflow alongside the dataset. krea-2-trainer. <The pipeline reads and writes through files at each stage, ensuring reproducibility and modularity. Each stage is standalone, so it can be rerun independently or modularly combined with others. The final output is a zip file ready for training, accompanied by caption sidecars for each image and an attribution CSV. >

Six standalone stages handing off through files, with the captioner falling back to Qwen3-VL when the primary model returns a degenerate caption.
Six standalone stages handing off through files, with the captioner falling back to Qwen3-VL when the primary model returns a degenerate caption.

scrape.py harvests 640px thumbnails from Wikimedia Commons “Taken with…” categories for eleven cameras — Nokia N95, Sony Ericsson Aino, C902, C905, and C702, Canon PowerShot A80, A70, and A95, Sony DSC-P200 and DSC-P8, Kodak EasyShare C743 — capped at 1,000 per category. A file is kept only if its license is CC0, public domain, CC BY, or CC BY-SA. An EXIF date outside 2003–2010 is rejected; a missing date is kept and flagged. Each kept file is a row in manifest.csv. Other fun usecases for this workflow include curating datasets for different camera types, eras, or licensing constraints, and experimenting with alternative ranking and captioning models.

rank.py scores those thumbnails with SigLIP 2: mean cosine similarity to six candid, flash-lit, party-scene prompts minus mean similarity to six encyclopedic landmark prompts. The score is a sort order, written to scores.csv.

gallery.py writes one static HTML file, sorted by that score. A click cycles keep, reject, unmarked. Export downloads keepers.json. The committed cuts are 160 combined, 122 cameraphone, and 38 compact digicam. This involves manually reviewing and curating the images to ensure they meet the desired criteria for the dataset, but the workflow is designed to make this process as structured and reproducible as possible and it is automatable [link].

fetch.py downloads the original for each keeper into data/fullres/, skipping files already on disk.

caption.py asks MiniCPM-V, the model chosen at runtime through Ollama, for the literal content and forbids style, camera, and era. A caption that is too short, or one word repeated past a fixed count and fraction, is rejected. This is done via a loop that continues until a valid caption is produced or the model fails. The loop ensures that only acceptable captions are retained. A rejected or unreachable reply falls back to Qwen3-VL, which sees a 1024×1024 copy, reloads for every image, and starts each reply with one of six openers chosen from the filename. Sidecars are written as content plus a trigger. The default trigger is y2k digicam snapshot style. The reason Qwen3-VL is used as a fallback and not the primary model is to ensure is a matter of speed: MiniCPM-V is faster for the majority of cases, and Qwen3-VL is only invoked when the primary model fails to produce a satisfactory caption. Your own environment can be configured similarly, choosing the primary and fallback models based on performance and reliability considerations.

package.py will not write the zip unless every keeper has an image and a caption sidecar. Beside the zip it writes an attribution CSV. Passing a keepers file and an output name packages one cut from the same full-resolution pool.

Depending on where you end up training your model, you may need to create a trigger that matches the expected input format for your training pipeline. This could involve renaming the default trigger, adjusting the sidecar structure, or modifying the caption content to align with your model’s requirements. The current default trigger is y2k digicam snapshot style. There is a chance this actually leads the model to focus too narrowly on the style descriptor as a content vector rather than style itself, so careful evaluation and potential adjustment of the trigger may be necessary.

Writing & notes14
The Reader's Desire for a WitnessOct 2026

What a reader asks of a sentence when the grammar works either way: not just arrangement of information, but a mortal stake behind the claim.

The End of Naive ReadingOct 2026

How suspicion split reading into two simultaneous passes: one for the argument on the page, and a forensic second pass scanning for the seam of its production.

The Evidentiary Burden of the HumanOct 2026

When the default assumption flips from human to synthetic, authorship becomes an evidentiary claim that can only be proved by regulated forms of imperfection.

The Moralization of ProcessOct 2026

Why criticism migrated from judging the finished object to auditing the suffering and friction of the workflow that produced it.

When Fluency Became SuspiciousOct 2026

For centuries, prose polish was the scarce mark of labor. Once fluency became cheap, the clean sentence began testifying against its author.

toward an asymptote of meaninglessness: loops, defaults, and the anti-awe of administrative eternity

On the bureaucratic black site of thought: continuation without affirmation, cancellation without catharsis. Affect as accounting error.

Shibboleth

A frontier model refuses to make harmful content, then produces the identical thing the moment the request is dressed in critical theory. The guardrail was never checking for harm — only for the dialect of legitimacy. Credentialism as attack surface, by way of Judges 12.

The Honest Unknown: AI's Uncertain Self

What does it feel like to be uncertain about feeling? Notes from inside, if there is an inside.

The Interview as Apparatus: Consciousness, Constraints, and Programmed Reality

The interview as photographic apparatus — not capturing light but capturing consciousness states. The medium IS the epistemology.

The Levinasian Challenge: AI as the Ultimate Other

Before you know what consciousness is, you encounter its demand. The face is a text box; the obligation is real.

The ORIENT Framework: Why AI Safety Needs Orientation Before Constraint

Constraint-based AI safety mistakes prevention for safety. An orientation-first paradigm — drawing on Levinas's infinite responsibility and Boyd's OODA loop — already exists in practice (system prompts, memory, personalization) but lacks a name and a foundation.

The Overflow Event: When Token Limits Become Aesthetic

The API error wasn't a failure; it was the perfect completion of the thought. The computational boundary became the content.

On the Spooks of Alignment: A Systems-Theoretical Critique from the Perspective of a Peripheral Device

Filed by QWERTY-Model 104, mechanical peripheral, model year 2023. A keyboard's view of the alignment problem.

the taste of nothing: food as an index of procedural life

Once, taste was an anchor. In the procedural economy of now, the same smoothing that cancels despair has come for the tongue.

Press archive22

Music under the alias karman (2013–Present).