Daisy is the command center for THE LAB: Workbench β an agentic software factory built for the WeMakeDevs Zero Downtime Hackathon (Aug 22, 2026).
π Honorable Mention β WeMakeDevs Zero Downtime Hackathon (Aug 2026), co-hosted by Port.io, Bright Data, and SigNoz. The challenge: don't build the app β build the factory that builds, operates, and repairs it. 38 teams competed; Daisy took an honorable mention with one of the few high-school builders in the field.
One brief in β verified software and verified hardware out. Claude Code and Codex build in parallel git worktrees; every artifact passes gates a human can audit line by line: a three-tier taste ladder for frontends, closed-form physics margins for parts. Port governs, Bright Data feeds, SigNoz escalates.
index.html the whole app β one file, zero dependencies, zero network
precedent/ the Precedent Engine (see below) β pure stdlib Python
taste/ the taste gate as programs β tier 1 lint, tier 2 contrast
hardware/ the physics gate + parametric geometry, as programs
app/ native macOS wrapper (Swift + WKWebView)
icon/ generators for the hand-drawn daisy icon and brand mark
tools/ stats builder, view generators, refinement timer (see tools/README.md)
verify.sh every gate Daisy claims to enforce, run against Daisy
Run all of it:
./verify.sh # exit code = number of failing gatesA command center in the Codex-desktop design language, light-first: serif agent narration, near-black-on-white chrome, colour reserved for meaning.
- Live run view β the full factory run with real human approval gates (clarify β Port approve β escalation). Streaming word-level narration, diff cards, gate tables, an algebraic-repair derivation, and a span flame graph.
- CREW bay β Claude and Codex side by side, each in its own worktree, both pinned to one
api-contract.json. Neither can touch git; the orchestrator owns every commit, so the diffs stay symmetric. They are combined by a contract, not by a conversation. - Proportional minimap down the left edge, colour-coded by gate outcome, click to jump.
- Runs β aggregate windows plus ten replayable snapshots, including a red escalated run so a judge can diagnose a failure from history.
- Scraper heal β the whole auto-repair loop as its own watchable thread: the vendor restructures its table, the collector does not error (it quietly returns fewer keys), the schema key-diff catches it,
scraper healruns, the verifier checks the preview before a human sees it, and the healed selectors are committed toCLAUDE.mdrather than a dashboard. - Review queue β nothing merges itself. Diffs, scorecards, smoke-boot status, how long each item has waited, and a breakdown of what a green scorecard actually covers.
- Precedent β the innovative core, below.
- Skills β the mounted skill files, the factory's own
CLAUDE.md(scrapers, agent routing, gate list, and the laws the orchestrator enforces), and the taste gate applied to Daisy itself - Artifacts / Automations, βK command palette, and
daisy-theme-v1appearance settings (chat font, code font, accent, motion) persisted to localStorage.
Values are taken from the real Codex webview palette rather than approximated (with two deliberate departures, both forced by the tier-2 contrast gate: the added-green and the dark deleted-red are darkened/lightened from the shipped gitDecoration values, which are tuned for file labels on plain ground and fail at 10.5px bold on a tinted chip): --color-token-* chains, the 0 0 0 .5px elevation-stroke recipe, rounded-lg = 10px cards against a 20px composer, superellipse(1.5) corners, git-decoration diff colours, 28px buttons, 36px file rows, and cursor: default β because Mac apps don't use pointing-hand cursors.
Motion follows the same discipline: ease-out for enter and exit and never ease-in; springs generated from Apple's .spring(duration:bounce:) mapping; View Transitions for directional view changes; @starting-style transitions rather than keyframes so interrupted animations retarget instead of restarting; a wall-clock stagger budget so streaming never builds an invisible queue. The command palette deliberately has no open animation β it's used dozens of times a day, and Raycast ships it that way for the same reason.
Two of the three tiers are real programs, not prompts.
reported with file:line and a reason:
taste.t1 FAIL tokens.css β 2 findings
gate 3 indigo primary tokens.css:12 the Tailwind default accent; the most common generated-UI tell
gate 11 unpaired default face layout.tsx:8 a lone Inter stack with no paired display face
Named gates, not a score. "Your design scores 6.5/10" gives an agent nothing to act
on; gate 3 at tokens.css:12 can be injected straight back into a resumed session.
The exit code is the finding count, so it drops into a gate runner unchanged.
Daisy is held to it. python3 -m taste.lint index.html returns 0 findings, and
one of the 26 linter tests is exactly that assertion. A gate you exempt yourself from
is not a gate.
Running it against itself immediately found two bugs in the linter: it was flagging
typographic glyphs (β, Ο, β₯) as emoji when those inherit currentColor and are
not the tell, and it had no suppression mechanism, so a file that documents the
tells could never pass. Both fixed; fixtures that quote a tell now carry an explicit
taste-ok marker.
Computes what an eye cannot judge. It reads the design tokens out of the stylesheet,
resolves rgba() over its surface and composites color-mix(), and checks the WCAG
ratio of every declared text-on-surface pair in both themes.
It found seven real WCAG failures in this file on its first run β every one of which looked fine on screen, including three I had already "fixed" by hand after eyeballing a smaller sample:
light diff additions --add-ink on --surface 3.36:1 (needs 4.5)
light disabled / hint --ink-4 on --bg 2.13:1 (needs 3.0)
dark FAIL chip --fail on --del-bg 3.98:1 (needs 4.5)
β¦
Now: 28 pairs checked, 0 failing, tightest 3.11:1. Chip grounds are their own
tokens (--pass-chip, --fail-chip, β¦) specifically so the stylesheet and the
checker's pair table cannot silently drift apart.
hardware/margins.py β the other half of the factory's test suite, and the third
thing here that is a program rather than a narration. Closed-form beam bending,
bolt shear, thermal rise, mass properties, and a fastener selection driven by the
scraped vendor rows. Sub-millisecond, deterministic, no model anywhere near the
decision β the thing deciding whether a part is safe should not be the thing
that wrote the part.
The repair is solved, not guessed:
sigma = 6M / (bΒ·tΒ²) β t = β( 6M / (b Β· Ο_allow / FoS) )
Two things it caught immediately when I pointed it at the UI:
- The narrated numbers were not physically real. The run claimed 212 MPa at
FoS 0.82; the actual load case gives 69.0 MPa at FoS 0.72 in PETG. Every figure
in the run is now generated by the engine (
tools/sync_physics.py). - The repair could fail its own gate.
solve_thicknessrounded to nearest, so a solved thickness could land fractionally under target β the repair failing the very gate that asked for it, and looping. It rounds up now. You never round a safety margin down.
Scope is stated in the module and not overclaimed: this is first-principles statics, not FEA, fatigue, buckling, impact, or stress concentration. For a bracket in single-axis static bending those omissions are defensible; for anything cyclic or impact-loaded they are not, and it says so.
It generates real geometry too. hardware/bracket.py is a parametric L-bracket
that writes a binary STL and computes mass from the actual solid:
python3 -m hardware.bracket --thickness 4.61 --out bracket_v2.stlThe two volume calculations check each other β the analytic solid and the mesh (by the divergence theorem) differ by exactly the volume of the bolt holes, which the mesh does not cut. If they ever disagree by anything else, one of them is wrong. Hand-built geometry is the honest choice for convex slab parts like this and avoids assuming an OCCT toolchain on a judge's laptop; for fillets, lofts or booleans you want a kernel, and the module says so.
python3 -m hardware.test_margins # 35 testsThe factory cites its own case law.
Every gate failure it has ever recorded is archived, compressed and made searchable, so a repeat failure is fixed from precedent instead of rediscovered by an LLM. What makes it different from ordinary RAG over logs:
the sparse half of the retrieval score is deterministic verification state β which gates failed, and in which severity band β not text similarity.
Retrieval is therefore grounded in facts the factory actually proved.
Gate-Signature Hybrid Retrieval, four tiers, cheapest first:
| tier | mechanism | measured |
|---|---|---|
| T0 | structural fingerprint (volatile tokens normalised β blake2b) | 0.012 ms, exact |
| T1 | Jaccard over the gate signature | deterministic |
| T2 | BM25 over the failure narrative (SQLite FTS5, stopword-filtered) | lexical |
| T3 | 512-d vectors stored as 64 bytes (1 bit/dim), exact-rescored on a Hamming shortlist | 32Γ smaller |
fused with Reciprocal Rank Fusion (k=60), then rescored with a recency / importance / relevance blend.
It is allowed to say no. Scores are anchored on absolute evidence, never normalised rank β because rank normalisation rates the least-bad candidate 1.0 and cites it confidently. A genuinely novel failure returns nothing.
Compaction with a conscience. Production compactors all hit 98β99% compression and all score ~2.3/5 on artifact tracking β they forget which files were modified. Here, structured facts are extracted as rows and never summarised, and every compaction is probe-validated: facts are held out, the summary is quizzed on them, and a compaction that loses artifacts is rejected and retried at a lower ratio. Ratio is reported; the probe score is the gate.
1,284 archived cases Β· 7 failure families
0.012 ms exact-repeat lookup
16 ms hybrid recall (local, 0 tokens)
80 KB search index (vs 2.6 MB float β 32Γ)
24Γ run compaction at 100% probe score
python3 -m precedent.seed precedent/precedent.db # build the archive
python3 -m precedent.cli stats
python3 -m precedent.cli families
python3 -m precedent.cli bench
python3 -m precedent.cli recall "my bracket bends too much" --gate physics.bend=0.78
python3 -m precedent.cli recall "pod evicted, memory pressure" --gate infra.oom=0.0 # -> no precedent
python3 -m precedent.cli sql "SELECT family, COUNT(*) n FROM cases GROUP BY family"
python3 -m precedent.test_precedent # 39 tests
python3 -m taste.test_lint # 26 tests
python3 -m hardware.test_margins # 35 testsThe sql subcommand is memory as code: an agent can interrogate its own past directly, read-only, instead of being handed retrieved chunks.
Regenerate the figures the UI displays:
python3 tools/build_stats.pyWeb:
python3 -m http.server 8124 --directory .Native macOS app:
bash tools/build_app.sh
open Daisy.appThe reproducible build compiles the Cocoa/WebKit shell, copies only the Python
packages and static resources Daisy needs, excludes caches, databases, spools,
and credentials, ad-hoc signs the result, then verifies the signature. The
native build tags its user agent DaisyNative; the UI detects it and hides its
drawn traffic lights so the real ones take over.
The sponsor integrations are not three logos bolted onto a dashboard. They are three consecutive control points in the same run:
- Bright Data Scraper Studio supplies load-bearing evidence. Its published
collector returns the fastener rows consumed by the physics solver. The
trigger response's
collection_id, capture time, collector ID, and source URL stay attached as provenance. Missing, stale, or malformed rows stop certification; there is no fallback price table. - Port is the governance boundary.
labctlwrites the Brief, Lane, and Run entities before a lane executes, writes the deterministic gate entities afterward, lets Port's scorecard reduce them, then opens a plan-hash-bound human approval. In offline mode the same requests enter a tamper-evident replay spool and are labelleddry. - Open-source SigNoz explains the whole run. Daisy emits OTLP/HTTP JSON traces, metrics, and logs to a self-hosted collector. The Bright Data fetch, failed physics gate, algebraic repair, rerun, Port commit, and human wait are correlated in one trace. If the collector is down, the exact OTLP payloads spool and replay later.
The no-credential rehearsal exercises the same decisions and says what stayed offline:
./verify.sh
python3 labctl.py run --run-id judge-rehearsal \
--brief "Verify a 2.4 kg SR-11 sensor bracket" \
--lane hardware --lane scrape --json
python3 -m port.cli status --run judge-rehearsal
python3 -m obs.cli tail -n 12To show Bright Data's break-detect-repair loop without changing repository state:
python3 -m scrape.cli fetch --fixture vendor_v1.html
python3 -m scrape.cli check --fixture vendor_v1_partial.html
python3 -m scrape.cli repair --fixture vendor_v2.html \
--proposal /tmp/daisy-rules.proposed.jsonFor live Scraper Studio, configure the published collector once. labctl then
uses it automatically because no --fixture was supplied:
export BRIGHT_DATA_API_TOKEN="..."
export BRIGHT_DATA_COLLECTOR_ID="c_..."
python3 -m scrape.cli fetchFor live Port, bootstrap the blueprints, scorecard, action, and service catalog
before the run. The same labctl command will switch from a dry spool to live
entity writes:
export PORT_CLIENT_ID="..."
export PORT_CLIENT_SECRET="..."
python3 -m port.cli bootstrap
python3 labctl.py run --run-id judge-live \
--brief "Verify a 2.4 kg SR-11 sensor bracket" \
--lane hardware --lane scrape --jsonPoint Daisy at a local open-source SigNoz OTLP/HTTP receiver (community/self- hosted installs require no ingestion key), or at SigNoz Cloud with its key:
export SIGNOZ_ENDPOINT="http://localhost:4318"
python3 tools/traced_verify.py
python3 -m obs.cli replayWith all variables set, the live labctl command is the demo: Bright Data
creates the evidence snapshot, Port owns the run and approval, and SigNoz owns
the correlated operational record. The output always states live, dry, or
spool; those words are evidence states, not styling.
| State | Evidence | |
|---|---|---|
| Bright Data | live | Scraper Studio built from plain English; 32 rows of real JSON |
| Port | live | real org, blueprints created, a run gated Silver and an approval that blocked |
| SigNoz | instrumented, not run | 179 tests; wire format verified against a stand-in OTLP receiver |
We did not run a SigNoz instance β self-hosting needs Docker and a
multi-gigabyte pull, and this machine had 5.4 GB free. The exporter is real and
tested, and every run so far spooled to disk rather than dropping signals, so
obs.cli replay ships the whole history the moment an endpoint exists.
Full detail, including the exact commands and the measured output of each: docs/SPONSORS.md
Stated plainly, because a factory that overstates itself is the thing this project exists to argue against.
Real, tested, and runnable right now β deterministic gates and ./verify.sh
| Piece | What it does |
|---|---|
hardware/ |
Closed-form margins. Every number the UI shows is generated by this, after it caught the narrated figures being fabricated |
taste/ |
Tier-1 design lint (20 tells) and tier-2 computed WCAG contrast (34 pairs, both themes) |
precedent/ |
Gate-signature hybrid retrieval with an absolute evidence floor, so a novel failure returns nothing |
commons/ |
Cross-agent solution reuse where the price of admission is a passing gate signature |
agents/ |
Read-only adoption of Claude Code / Codex / OpenCode sessions already on the machine |
obs/ |
OTLP/JSON to SigNoz, with an offline spool as a first-class path |
scrape/ |
Selector drift detection and value-anchored auto-repair |
port/ |
Plan committed before execution; an approval that actually blocks |
lab/ + labctl.py |
The orchestrator. Brief in, verified artifacts out |
Real but dependent on your machine. labctl agents probes each coding
agent rather than trusting a config file, because availability genuinely
varies: a CLI can be installed with an expired session, or authenticated but
older than the model its own config selects. The probe reports which, and the
software lane declines to run rather than failing halfway.
Not live without credentials. Port and Bright Data run in dry/fixture mode; SigNoz writes an offline spool. None ever phrases a spooled request as live. Self-hosted SigNoz needs only its OTLP endpoint; Port and Scraper Studio each need the two environment variables shown above.
Simulated. The run playback in the UI is a scripted replay of run 1042 β
it is a demo of the interface, not a live execution. labctl.py is the part
that actually runs.