TicketStub is a keepsake studio for events: you paste a link to a concert, game or show, the app researches the night, and it produces a personalized commemorative ticket stub with original artwork that you can edit, approve, download and, eventually, order as a print. Our team, Jevelopers, built it for neatHack 2026, an online hackathon that ran October 10-12, 2026. I was team captain and wrote a large share of the code, but this was a team effort and the credits are at the end of the post.
The interesting part is the pipeline behind the stub: research that tracks where every fact came from, image generation that never draws text, durable jobs that survive a crash, approval bound to an exact design version, print checks, and cost controls meant to run before any paid API call.
Status: this is a hackathon prototype. The customer studio runs end to end in demo mode with simulated research and art. Most specialist components are tested libraries that are not yet wired into the app. Nothing here takes real payments or ships physical prints.
Problem
Mobile tickets replaced the paper stub that people used to keep from a night out. Our idea was to bring it back as a designed object: real facts about the night, artwork that fits the event, and a printable file at the end.
Solution
On the first day the team wrote an architecture kit with one goal: turn an event URL into researched facts, original artwork, customer revisions, approved tickets, downloadable files and an authorized print order, while recording what the workflow cost. It also set a few rules:
- One owner for each business record. The app owns customers, orders and approvals. The harness owns workflow execution. Finance owns spending.
- Meter billable attempts from the first working call, reserve budget before execution, and keep missing or uncertain billing data for reconciliation instead of guessing.
- Aim for a narrow but complete demonstration rather than a broad, half-working platform.
We followed the first rule closely. The last one we only partly met, as the status table shows.
Architecture
This post covers six repositories: getticketstub.com (the Next.js customer app and composition root), event-intelligence (research and fact provenance), creative-engine (briefs, image generation, design versions), print-production (composition and preflight), cost-intelligence (pricing, budgets, ledger) and agent-harness (durable workflow state and telemetry). The organization has a few more, such as brand kit, shared contracts and fulfillment connectors.

Each specialist repository is a library, not a service. The app vendors pinned subsets into src/server/vendor/, each with a MANIFEST.json recording the upstream commit and a SHA-256 per file. Today that covers agent-harness, creative-engine, cost-intelligence and fulfillment-connectors. Event-intelligence and print-production are not vendored; their handoffs exist only in design documents.
That split let four people build and test in parallel over a weekend. The cost is integration: much of the remaining work is agreeing shared contracts between repositories.
Implementation
Event research and structured extraction
The app’s /api/research route turns a link into a list of facts. Every fact carries a source, a confidence and a provenance label (live, estimated, simulated or pending) that the studio displays.
In live mode the route reads schema.org Event data from JSON-LD, falls back to the page title, and gets weather from Open-Meteo. A date guessed from page text gets confidence 0.5 and two alternatives (the day before and after) for the customer to choose from.
A language model can add up to four extra facts, but it must quote the page. The route only trusts a fact as live if the quoted evidence actually appears in the fetched text. Otherwise the fact is downgraded to estimated and its confidence is capped:
// getticketstub.com/src/app/api/research/route.ts
// Only trust as "live" when the quoted evidence really appears on the fetched page.
const grounded = typeof i.evidence === "string" && i.evidence.trim().length > 0 && i.evidence.length <= 2000 && lowerText.includes(i.evidence.toLowerCase());
return {
...
confidence: Math.min(grounded ? 0.85 : 0.5, typeof i.confidence === "number" ? i.confidence : 0.6),
provenance: grounded ? ("live" as const) : ("estimated" as const),
};
This does not prove the fact is true, only that the model did not invent the quote. It was the level of rigor we could ship during the event.
The event-intelligence repository goes further, as separate private components. Its SafeFetcher validates URLs and DNS, pins connections to vetted addresses, revalidates redirects and enforces hard limits per run:
// event-intelligence/src/security/controlled-fetch.mjs
export const DEFAULT_RUN_LIMITS = Object.freeze({
requests: 30,
redirectsPerFetch: 5,
concurrentFetches: 4,
connectMilliseconds: 10_000,
totalMilliseconds: 30_000,
wireBytesPerRequest: 10 * 1024 * 1024,
...
});
It also has deterministic JSON-LD, HTML and text-PDF extraction, an encrypted evidence store, and a privacy boundary that quarantines fetched content until a trusted review approves the public facts. Its README is clear that this is not yet a public research API.
AI image generation and personalization
One early decision: the image model never draws text. Names, dates and venues are set by the stub template in real fonts over a text-free scene. Image models still misspell words, and a wrong date on a printed keepsake is the error we most wanted to rule out.
Personalization goes into the prompt instead. The app’s prompt builder turns researched facts into scene constraints, and adds their opposites as negatives so a rainy night does not come back sunny:
// getticketstub.com/src/customer/studio/research/artPrompt.ts
} else if (/rain|drizzle|shower/.test(w)) {
weather = "rainy, wet reflective streets,";
negatives.push("snow", "clear blue sky", "harsh sunshine", "dry dusty ground");
} else if (/dry|clear|sun/.test(w)) {
weather = "dry, clear air,";
negatives.push("rain", "puddles", "umbrellas open against rain", "snow");
}
Event type picks a scene, the venue is “described, not copied”, and remix chips such as “moodier” add a mood line. Live art generation is capped at 10 images per day per account or device, and 30 per IP.
The creative-engine repository is the fuller version. Its library API offers generate, edit, inspect, compare, restore and brief operations around injected ports. Every result is an immutable version in SQLite with content-addressed bytes, so restore never overwrites history, and a missing port returns unavailable rather than a fake success. It has OpenAI and OpenRouter image adapters, but every live gate exits with code 2 and makes no call. I called no image API for this article.
Durable jobs and checkpoints
If a process dies after a provider has charged for an image but before we saved it, a naive retry pays twice. The agent-harness repository addresses that using Node’s built-in node:sqlite and no third-party runtime dependencies.
A workflow moves through a small, explicit state machine:
// agent-harness/src/internal/durable-store.js
const TRANSITIONS = new Map([
['queued', new Set(['running', 'review_required'])],
['running', new Set(['reconciliation_pending', 'review_required', 'succeeded', 'failed'])],
['awaiting_response', new Set(['running', 'reconciliation_pending', 'review_required', 'succeeded', 'failed'])],
['reconciliation_pending', new Set(['running', 'review_required', 'succeeded', 'failed'])],
['review_required', new Set()],
...
Every state change runs in a BEGIN IMMEDIATE transaction that compares the expected revision and the worker’s fencing token, then writes the event and an outbox entry together. A stale worker or an expired lease cannot write. A provider response, its hash and the proposed next checkpoint are saved as one receipt. After a restart, recovery verifies the hash and advances the checkpoint without repeating the external call, and a completed receipt blocks redispatch of the same operation.
The design document says plainly that this is durable local state and deduplication, not exactly-once execution. An unknown outcome stays pending for reconciliation instead of being guessed. The controller rejects mode: "live", so today this runs in mock mode and tests only.
Human review and correction
AI research gets things wrong, so the customer is the final reviewer, and we tried to make that review explicit.
- Unsure facts are questions. A low-confidence fact shows up in the editor’s Facts panel with its alternatives. Missing details, such as where an event took place, become prompts (“Where was it?”).
- Inclusion is separate from verification. Adding a fact to the stub does not mark it as verified, and the panel says so.
- Corrections keep history. In event-intelligence, a customer answer is stored as
customer_supplied, not “sourced”, older versions are kept, and a later source that disagrees creates a review question instead of overwriting the answer. - Approval binds to bytes. The app issues a signed approval bound to the exact design version, art hash and facts hash, for one purpose (
print.composeorartifact.download). It explicitly does not authorize a purchase, payment, order or asset rights.

Creative-engine adds machine inspection first. A deterministic gate checks hashes, decodes the image within limits, and checks the brief, unresolved facts and asset permissions before a visual model is asked narrow questions. A favorable model answer cannot override a failed check, uncertain evidence goes to human review, and automatic repair is capped (two claims, 60 seconds and three simulated units in the fixture policy).
Print-production checks
Print-production, where most of the commits are Zach Wright’s, is where the stub becomes a physical-dimension file. It composes in millimetres, measures and shapes text with pinned fonts (no host font fallback), and builds SVG output before rendering through a pinned Chromium.
Preflight checks geometry, effective raster DPI, bleed coverage (including rotated art), safe zones, clipping and font integrity. Repairs are limited to shrinking or moving text within bounds. Names, dates, seats and serials are never rewritten, overflow blocks instead of truncating, and anything riskier returns NEEDS_EXTERNAL_REVIEW.
The limits matter. The offline calibration renders a synthetic 4 x 2 inch fixture to PNG and PDF and checks both. The profile is sRGB, with no CMYK, PDF/X or printer certification claimed, and supplier eligibility stays blocked even when every local check passes.
Cost tracking and budgeting
Every paid call was meant to go through Finance first. Cost-intelligence implements pricing catalogs, usage intake, budget reservations (authorize, markDispatched, changeBudget), an append-only ledger and scoped reporting and exports, on PostgreSQL.
Two choices I would reuse anywhere. An unconfigured call returns unavailable instead of a financial zero, so a missing integration cannot look like “this cost nothing”. And unknown usage stays unknown, rather than totals quietly summing only the known parts.
In the app, the config-gated /api/creative route composes the vendored creative-engine with the Finance package and the harness decision port, and the app’s tests include a “Finance-first barrier” case that checks paid routes are denied without the runtime override. Settlement, release and reconciliation are still unavailable facades, and the financial release gate is open.
Evidence
The status review and local runs below were captured on 2026-10-21 at commits 9fd9512 (getticketstub.com), 333c6f0 (agent-harness), a4df4ef (event-intelligence), 0430b4a (creative-engine), 4ca2b83 (print-production) and 521e4be (cost-intelligence).
What works, what is a prototype, what is not built
This table reflects the READMEs and source at the commits listed below, plus what I ran locally.
| Component | What works | Prototype/stub | Not built |
|---|---|---|---|
| Customer studio (getticketstub.com) | Runs locally with no keys: intake, printing reveal, five styles, fact picker with provenance labels, editing, versions, wall, PNG export, magic-link sign-in, SQLite storage, backups | Demo research fixtures, simulated agent replies, procedural or demo art; sandbox checkout; wallet passes and QR codes simulated | Live payment acceptance, physical fulfillment, production access and budget controls, integrated v1 acceptance |
| Event research | App (live mode only): JSON-LD and title extraction, weather, quote-grounded model facts. Event-intelligence: safe fetch, extraction, evidence store, correction history, offline tests | Event-intelligence components are private and not wired into the app | Public research API, complete source traversal, canonical fact selection, scanned-PDF and screenshot inspection |
| AI image generation (creative-engine) | Library API with injected ports, immutable versions, deterministic inspection, bounded repair, offline tests | OpenAI and OpenRouter adapters exist, but live gates exit 2; app art route is a direct prototype path | Live mode, durable handoff, accepted cross-repository contracts |
| Durable jobs (agent-harness) | SQLite checkpoints, leases and fencing, receipts, outbox, migrations, crash and restart tests | Private bounded controller, mock mode only; telemetry and decision transports are opt-in | Deployed workflow, live mode, AH-01 and AH-03 acceptance |
| Human review | Unsure-fact questions, customer corrections, signed approvals bound to version, art and facts hashes | Approval consumers are checked with public fixture keys only; versioned signing-key work is on an open PR | Product and print-layout review sign-off for print readiness |
| Print production | Offline calibration render, composition, typography, preflight, bounded repair, bundle byte verification | Candidate adapter against an unaccepted shared-contracts development version; sRGB only | CMYK or PDF/X output, approved supplier specification, supplier eligibility, app integration |
| Cost tracking (cost-intelligence) | Pricing, usage intake, budget reservations, ledger, reporting and exports on PostgreSQL; app-side art quota | Shared contract pinned as proposal-only; host authority issuers not real yet | Public settle and release, reconciliation, financial release gate |
Demonstrations and what I ran
I ran everything locally with no provider keys and called no paid API. Test runs used a Node 22.23.3 Linux container.
- Studio demo. The dev server’s
/api/healthreported"mode":"demo". I captured the screenshots above with all non-localhost browser requests blocked. - getticketstub.com: 1,305 tests, 1,303 passed, 1 failed (a landing-page reduced-motion test I did not investigate), 1 skipped. The Finance-first barrier test passed.
- creative-engine: the
apitarget passed 61 of 61 tests; theversionstarget passed 253 of 254, with one schema-migration replay case failing. - agent-harness:
make checkpassed. Its owned test runner did not complete in my container, so I ran the durability, foundation and recovery files directly: 42 of 42 passed. That is a partial run.
All of these use synthetic fixtures. They show components behaving as designed in isolation, not real-world validation or an integrated journey.
Limitations
TicketStub is a hackathon prototype. The app and event-intelligence repositories had commits as recently as October 21, 2026; the other four were last updated on October 15.
- The full journey from link to printed stub does not exist yet. The integrated v1 acceptance issue is open.
- Demo mode is the default. Research, art and agent replies are simulated unless live mode and provider keys are both configured, and enabling them requires the team’s budget approval.
- No real payments are taken. With no payment provider configured, orders stay in sandbox, and every physical variant is preview-only or unavailable.
- Print output is not certified for any printer or supplier, and supplier eligibility is blocked by design.
- Event-intelligence and print-production are not integrated into the app. Cross-repository contracts are proposals awaiting owner agreement.
- Durability, inspection and Finance behavior is tested only offline with synthetic data, never against real provider traffic.
What I am happiest with is that the repositories say all of this themselves. Nearly every README separates “implemented locally” from “pending”, and several runners exit with a failure code rather than report an acceptance they cannot prove.
Resources
- getticketstub.com: no license file; source-available on GitHub. Commit
9fd9512. - agent-harness: MIT License for original project code (banner artwork excluded, see its COPYRIGHT.md). Commit
333c6f0. - event-intelligence: no license file; source-available on GitHub. Commit
a4df4ef. - creative-engine: no license file; source-available on GitHub. Commit
0430b4a. - print-production: no project-wide license file (bundled fonts keep the SIL Open Font License); source-available on GitHub. Commit
4ca2b83. - cost-intelligence: no license file; source-available on GitHub. Commit
521e4be.
If you have an idea that needs a working prototype with this kind of separation between what is real and what is simulated, that is the work behind our Prototyping and MVP Development service.
TicketStub was built by the Jevelopers team for neatHack 2026: Timothy Wayne Gregg (CompleteDotTech, team captain), Lars van der Zande (lmvdz, brand, editions and studio design), Zachary Wright (zwright8, print-production) and Crystal Aguilar (lajefahemp-collab, landing page and documentation). Git history in these six repositories shows commits from CompleteDotTech across all of them, lmvdz in getticketstub.com, zwright8 in print-production and cost-intelligence, and a few commits from an automated Codex identity.
