ZYEL LAB / BUILD THE WORKFLOW
Build a bridge that can explain its changes.
By Chason Arthur · Project Lead
Start with one observable result: a callback changes one synthetic task once, an identical repeat changes nothing, and a newer owner edit is preserved. We will build the boundaries around that result before considering a real Codex adapter.
Scope: original synthetic code, browser memory or local loopback HTTP. No private conversations, credentials, real Codex executions or production writes. The actual owner bridge informed the architecture; its private implementation and records are not included.
STEP 1
Run a bounded local workspace.
- Objective and prerequisites
- Use a dedicated checkout and Node.js 24.19.0, the runtime tested for this lesson. Know basic JavaScript ES modules and HTTP. No npm runtime packages or accounts are required. A modern browser needs Web Crypto and ES modules; loopback is a secure context in supported browsers.
- Recommended implementation
- Start the companion from its own directory. It binds only to
127.0.0.1and keeps the board in memory. Stop it with Ctrl+C. A static host runs the same browser model without proving a server boundary.
# From the new trusted, extracted source directory: node lab/codex-bridge/tools/verify-source.mjs cd lab/codex-bridge node --version node --test tests/*.test.mjs node server.mjs # Open http://127.0.0.1:4264/lab/codex-bridge/
Source setup: use the reviewed source snapshot supplied with the episode packet, preserving its folder tree. Public source-download availability remains pending until the integration writer publishes the reviewed artifact. Compare the archive SHA-256 with the trusted reviewed delivery first. An attacker can replace both the ZIP and its embedded manifest or verifier; embedded hashes alone do not establish publisher authenticity or malware safety. Do not execute untrusted source. Extract into a new empty folder, preserve its tree and run the included bounded Node verifier before the exercise. It checks listed bytes and rejects unsafe paths/linked parents; it does not inspect unlisted files or protect against concurrent filesystem changes. Required files include the complete lab/codex-bridge/ lesson, companion, producer and tests, plus the exact lab/shared/ dependencies listed in that manifest and the existing Lab license. Do not copy private owner runbooks or an entire production checkout.
Source profile: the supplied module/style URLs use lab_rev=bridge-66f5555-c887-efeb3e798ef5, a development namespace. It is not a stamped publication revision or proof of a production cache upgrade. Node imports are separate. SOURCE-QUICKSTART.md and source-manifest.json identify the actual code and shared foundation; this snapshot contains no selected-still media. Other Zyel navigation links are online references, not bundled apps.
The server’s explicit file allowlist serves the lesson and its reviewed shared shell resources. It excludes server.mjs, tests, the producer CLI and private review files from static HTTP delivery. The source repository remains the place to inspect those development files.
- Practical alternatives and tradeoffs
- A browser-only fixture is easiest to publish and resets cleanly, but cannot demonstrate HTTP authorization. A local server shows real status codes and request bounds without infrastructure. A deployed service needs an independently reviewed identity, persistence and operational plan; this lesson does not turn on one.
- Common pitfalls
- Do not bind to all network interfaces, paste a real token into the demo, treat a display label as identity, or mistake a successful localhost request for production acceptance.
- Verification and result before proceeding
- The mode badge must say LOCAL HTTP FIXTURE when the companion runs. On static hosting it must say BROWSER FIXTURE. Read the initial board: revision 1, task version 1, phase requested.
STEP 2
Separate Codex capability from the adapter contract.
- Objective and prerequisites
- Identify the supported source before designing a callback. Finish step 1 and read the official documentation linked below.
- Recommended implementation and explained code
- Our teaching adapter accepts a curated event object. It is an original application contract, not an OpenAI API. The owner’s configured system uses already-authorized source tools and a private guarded producer route. It does not implement a generic webhook that discovers private conversations on every device.
// Generic application boundary: this does not call Codex.
async function onReviewedWorkResult(metadata, bridge) {
const batch = await prepareReviewedBatch(metadata);
return bridge.preview(batch); // A human inspects before any apply.
}
// prepareReviewedBatch is an adapter boundary, not a provided Codex API.The official Codex SDK guide describes server-side control of local threads. The app-server guide describes JSON-RPC clients, approvals and streamed events; it currently marks app-server and its WebSocket transport experimental and unsupported for production. This workshop installs neither. Supported accessible local tasks do not establish access to all private ChatGPT or Codex cloud conversations.
- Practical alternatives and tradeoffs
- An explicit producer command is easy to audit and fits the inspected owner workflow, but needs deliberate execution. A permitted local lifecycle integration may reduce repetition, but needs version-specific behavior and error handling. A scheduled authorized reconciliation can inspect accessible work, but unavailable sources remain held. Do not substitute transcript-file scraping or another permission path.
- Common pitfalls
- The JSON examples below are our fixture endpoints. Do not present them as OpenAI endpoints. Do not expose an experimental unauthenticated listener, assume “turn complete” means the whole task is done, or copy an agent’s full response into a public board.
- Verification and result before proceeding
- Use the local producer sequence below. It saves the exact immutable batch and plan, and Apply requires the plan ID you just reviewed. The health response reports
codex_calls: 0. These two device labels simulate separate producers on one local fixture; they do not establish a connection between physical computers.
node producer.mjs inspect node producer.mjs prepare --run=laptop-take --device=laptop --message=message-laptop-01 node producer.mjs validate --run=laptop-take node producer.mjs preview --run=laptop-take # Read the saved batch and preview. Copy the exact printed apply command. node producer.mjs apply --run=laptop-take --confirm=PRINTED_PLAN_ID node producer.mjs receipt --run=laptop-take node producer.mjs repeat --run=laptop-take node producer.mjs prepare --run=desktop-take --device=desktop --message=message-desktop-01 node producer.mjs preview --run=desktop-take
PRINTED_PLAN_ID is an explicit placeholder, not a runnable default. The preview prints the complete command with its actual 64-character plan ID. Plans expire after sixty seconds. A second terminal on the same machine may inspect the desktop run: its thread provenance differs while the same board task advances from the current version.
The CLI stores synthetic runs under .bridge-fixture-runs/RUN/run.json in your working directory. Batch digest checks prevent a changed payload from reusing its review; a per-run local lock rejects concurrent commands. It records dispatch before the request, and an uncertain Apply blocks further writes until the exact event receipt resolves. A missing receipt while dispatch may be pending is not permission to retry. Inspect an interrupted command and its saved lock/journal; do not delete evidence or create a new run to bypass uncertainty. If an interrupted command retained its lock, the receipt command still performs read-only outcome inspection. It does not alter the journal or delete/steal that lock, and Apply remains blocked. Lock metadata records command/PID/time without guessing whether a process is alive. This local journal is not a durable production transport receipt.
STEP 3
Keep task identity across devices.
- Objective and prerequisites
- Use the existing task mapping instead of creating one task per device or mention. Begin with the inspected synthetic board.
- Recommended implementation and explained code
- A stable source task identifies the work. Thread and message identifiers provide provenance; the device label is descriptive only. A known board task and its expected version prevent an accidental new record or stale overwrite. The fixture accepts exactly one event per batch to keep review readable.
{
"source_task_id": "demo:bridge-workshop",
"source_thread_id": "thread-laptop",
"source_message_id": "message-01",
"device_label": "Demo laptop",
"board_task_id": "TASK-101",
"expected_task_version": 1,
"sensitivity": "work_metadata",
"privacy_reviewed": true
}validateBatch allowlists keys and bounds identifiers, text and total body size. An unknown field is refused. An explicit privacy declaration is necessary but cannot prove the content is safe. A human still reviews the short summary; the credential-shaped text check is only a limited backstop.
- Practical alternatives and tradeoffs
- A global source mapping makes repeated mentions converge on one task, but migrations need a clear conflict policy. Per-device task records are simpler initially but create duplicates. Content similarity can suggest a candidate mapping, but must not silently merge unrelated work; retain an unresolved mapping hold.
- Common pitfalls
- Do not use a computer name as authentication, derive identity from free text, reuse another task’s board ID or transmit raw chats and customer records.
- Verification and result before proceeding
- Prepare a batch. Inspect its exact JSON. Change the device to Demo desktop: the source task and board task remain the same, while provenance changes. Prepare again after reviewing the new message. Uncheck the privacy declaration and Validate; the operation must hold without changing revision 1.
STEP 4
Preview an immutable change.
- Objective and prerequisites
- Separate “I intend to write” from “the reviewed write is still safe.” Restore the privacy declaration and inspect the current board.
- Recommended implementation and explained code
- Canonical JSON sorts object keys before hashing. The batch binds the board revision and SHA-256, task version and exact event. Preview returns a plan ID and the before/after change. The fixture retains at most ten plans, each valid for sixty seconds.
const planId = await digest(batch);
plans.set(planId, {batch: structuredClone(batch), createdAt: now()});
// Apply later requires this exact stored batch and current board guards.A digest detects mismatched bytes; it is not a signature, permission or proof of a human review. The server also checks the permitted producer scope and task mapping. Changing the form invalidates the current preview rather than quietly applying new content under an old approval.
- Practical alternatives and tradeoffs
- Revision-only compare-and-swap is compact but needs a trustworthy revision discipline. Hash plus revision helps detect unexpected byte changes but adds work and still needs atomic persistence. A server-issued signed plan can support a stateless design, but requires expiry, key rotation and replay analysis; this memory fixture avoids those credentials.
- Common pitfalls
- Do not hash one payload then apply a reconstructed one, share an approval across tasks, or clear an owner edit to make a stale preview pass.
- Verification and result before proceeding
- Validate then Preview. The panel should show requested/version 1 to in_progress/version 2, while the board remains unchanged. Click Simulate a newer owner edit. Apply the older preview: expect
workspace_conflict, preserving the newer summary. Inspect and refresh guards, then review and prepare a new batch.
STEP 5
Apply once, then prove it.
- Objective and prerequisites
- Make a repeated callback harmless and keep the actual outcome visible. Use a fresh valid preview from step 4.
- Recommended implementation and explained code
- The event key binds stable source task, thread and message. Its digest identifies the exact content. An identical processed key returns the original receipt before stale-version checks. Reusing the key with different content conflicts. After a successful apply, inspect the board and repeat the exact preview.
const processed = ledger.get(sourceEventKey);
if (processed) {
if (processed.eventDigest !== eventDigest) throw eventConflict();
return {would_change: false, changed: [], receipt: processed};
}The excerpt explains the algorithm; the complete running implementation is bridge-core.mjs. The fixture stores receipts in memory. A real multi-process service requires a transaction or lock spanning the version check, task update and unique event insert, plus exact backup and recovery behavior. A JavaScript Map is not durable storage.
- Practical alternatives and tradeoffs
- A unique database event constraint and transaction supports concurrent producers, at the cost of schema/retention work. An outbox supports reliable downstream delivery, but adds a dispatcher and recovery state. Best-effort fire-and-forget is short code but cannot establish whether an uncertain callback changed the board.
- Common pitfalls
- Do not create a new event ID merely because a response was lost, report a pending write as failed without checking, or automatically mark the task done because one adapter call succeeded.
- Verification and result before proceeding
- Apply, Read back and Repeat identical preview. Observe exactly one task-version increment,
would_change: falseandchanged: []. Change the summary while retaining the processed message; prepare/preview must conflict. Use a genuinely new reviewed source message for a new update.
STEP 6
Handle scope, timeouts and logs.
- Objective and prerequisites
- Make transport failure and insufficient permission explicit. Use the local HTTP companion to test the actual HTTP boundary.
- Recommended implementation and explained code
- The companion has two public dummy bearer strings: a reader and a producer. The server checks scope on each write, validates content type and a 4 KiB body bound, allows only its loopback Host/same origin, sets five-second receive timeouts and caps each fixture principal to sixty requests per minute. These are teaching controls; the dummy strings are not secure credentials.
| Endpoint | Method/scope | Purpose |
|---|---|---|
./api/state | GET reader/producer | Current synthetic board, guards and receipts. |
./api/validate | POST producer | Validate a curated batch. |
./api/preview | POST producer | Review an immutable proposed change or no-op. |
./api/apply | POST producer | Apply the exact reviewed plan. |
./api/receipt?event_id=… | GET reader/producer | Inspect whether a known event committed. |
The client aborts its wait after four seconds. Aborting a request cannot undo a server commit. For an uncertain apply, this page retains the exact event/batch, locks all writes and uses Read back current state to inspect the exact event receipt. A matching digest confirms the retained event committed. No visible receipt while dispatch may still be pending leaves uncertainty and the write lock in place. Preserve the original transport receipt and inspect that outcome before any retry. Retry read-only availability checks with bounded backoff if appropriate. Honor server retry guidance; do not use logging or retries to amplify traffic.
- Practical alternatives and tradeoffs
- Existing owner sessions with same-origin CSRF/version checks fit a private browser. A separately reviewed producer principal fits server jobs. Neither can be replaced by an arbitrary device ID. A durable queue can smooth bursts but needs a worker, cost and dead-letter policy. The lesson creates none of these production resources.
- Common pitfalls
- Never log full request bodies, tokens, chat text or customer data. The fixture log keeps only twenty timestamp/event/result entries in memory; restarting clears them. Production logging needs separately evidenced retention, access, redaction, sampling and cost controls. Generic error responses should not reveal stack traces or infrastructure.
- Verification and result before proceeding
- Choose Reader and Preview: expect forbidden, with no task change. Inspect the minimal log and confirm summaries and dummy bearer values are absent. Run the HTTP tests for missing/wrong scope, media type, oversized bodies and method handling. This is not an abuse test against a public endpoint.
See Node 24 HTTP documentation for timeout behavior and OWASP REST Security for access control, bounded validation and safe errors.
AUTHORITY CHECKPOINT
Aborting a request is not task cancellation.
AbortController stops this client’s wait or transport. The server may already have committed. It does not undo a write, change the board task to cancelled, or stop an executor.
An inspected successor to the owner’s configured bridge was published on October 25, 2026 at 14:43:30 UTC. Its native cancellation path requires an explicit existing mapped task, current compare-and-swap guards and a verified human-owner cancellation instruction bound to the correct task, thread and message. The original instruction must be newer than both the prior sync event and the latest native owner edit; replacing that time with a later processing time would revive stale intent. Prior proof is retained, and reactivation needs a separate explicit owner instruction.
The local exercise does not implement authoritative task cancellation. No real task was cancelled by that native release. A summary, assistant assertion or verified: true flag alone cannot establish the human’s authority. The inspected native capability does not create a public ingest endpoint, grant access to private chats or prove a future scheduled dispatch.
| Action | Meaning | What this exercise can verify |
|---|---|---|
| Abort a request | Stop waiting; preserve an uncertain write and inspect its exact receipt. | Actual local HTTP timeout, write lock and readback. |
| Cancel a board task | A separately authorized native state transition, with fresh mapped identity, owner intent and conflict guards. | Explanation only; no cancellation endpoint or task mutation is supplied. |
| Stop an executor | A separate execution-control action under its own permissions. | Not implemented or implied by either action above. |
| Reactivate cancelled work | A separate new owner decision, retaining prior proof and existing holds. | Explanation only; an ordinary progress callback cannot stand in for it. |
- Practical alternatives and tradeoffs
- A local abort keeps the interface responsive but leaves the authoritative outcome to readback. Native cancellation records an owner decision but must guard chronology and concurrent edits. A visible hold is appropriate when intent or source access cannot be verified; guessing creates the wrong authority.
- Common pitfalls
- Do not label a timeout “cancelled,” delete the task or historical evidence, regenerate instruction timestamps, or treat cancellation as deployment/completion. Do not infer executor termination.
- Verification and result before proceeding
- Use the local timeout tests to prove that aborting the wait can coexist with a committed event. Confirm the UI retains its uncertain outcome until the exact receipt resolves. This proves the request boundary only; native cancellation requires its separate verified owner workflow.
STEP 7
Let Scrum drive the wall.
- Objective and prerequisites
- Separate task authority, artifact evidence and scheduling. You should be able to explain the readback from step 5.
- Recommended implementation and explained code
- The configured wall reads native task status from the board. Sidecars carry separate preview receipts, layouts and approved asset references. A receipt describes exactly what was verified; it does not change the task to done. An inaccessible source stays an explicit candidate or hold.
// Original teaching shape, not the private wall's storage schema.
const wallTile = {
task: boardSnapshot.tasks[0], // Board remains authoritative.
evidence: {verification: 'local_review', scope: 'synthetic_callback'},
publication: 'not_deployed'
};At inspection on October 25, 2026, the existing single reconciliation routine was enabled on a daily flexible 22:00 America/New_York schedule. Its last recorded run was 2026-10-25T02:38:48Z. A future dispatch and next-run timestamp were not verified. That private routine is not installed by this Lab and is not proof that every private chat is accessible.
- Practical alternatives and tradeoffs
- A scheduled reconciliation is inspectable and bounded but can be delayed and only sees authorized sources. An explicit producer update provides timely evidence but requires deliberate execution. Event-driven delivery needs a supported event source and its own reviewed access contract; do not create an unverified webhook or duplicate schedule.
- Common pitfalls
- Do not infer done from an iframe load, merge local and live proof, overwrite a newer board status with an old wall receipt, or treat a scheduled future run as already executed.
- Verification and result before proceeding
- Select Done or Deployed verified and prepare a new message. Preview must hold: this fixture has no trusted live deployment evidence. Reset and prove the ordinary in-progress flow still works. The wall’s screenshot/link fallback must respect framing restrictions rather than weakening them.
STEP 8
Test, release and maintain the boundary.
- Objective and prerequisites
- Package only what was tested and preserve an exact rollback. Complete successful, repeated, conflicting and forbidden flows.
- Recommended implementation and explained code
- Run core and HTTP tests. Independently inspect desktop, 390-pixel and 320-pixel layouts, keyboard order, status announcements, contrast and reduced motion. Record original actual-browser frames after the source is frozen. The publication allowlist contains only reviewed static lesson files; the companion remains a local exercise unless separately authorized.
node --test tests/*.test.mjs node --check bridge-core.mjs node --check app.mjs node --check server.mjs # Freeze the exact source, review it, then record individual frames.
- Practical alternatives and tradeoffs
- A narrow static release minimizes operational scope. A server release can demonstrate durable callbacks only after identity, transactions, ownership, backup/recovery, observability and approval are proven. Preserve private evidence separately; it is not public source content.
- Common pitfalls
- Do not publish tests/private runbooks by recursively copying a repository. Do not overwrite unrelated site files. Do not claim benchmark results from intuition; this workshop has functional checks, no production latency or throughput benchmark.
- Verification and result before proceeding
- Capture exact source/file hashes and review receipts. Back up overwritten allowlisted paths, record new paths, publish only approved bytes, and verify actual URLs/readbacks. Rollback restores those exact preimages and removes only release-added files. Prepared, reviewed and published remain different states.
- Maintenance exercise
- Add a second synthetic task without weakening mapping or version checks. Test a wrong mapping, a new thread for the same task, a stale revision and a lost apply response. Explain why the board is still authoritative.
Versions, sources and evidence limits
Implementation baseline: Node.js 24.19.0, browser ES modules and Web Crypto; zero runtime npm dependencies. Official documentation checked October 25, 2026. Codex SDK/app-server packages are not installed, pinned or executed by this fixture, so no SDK runtime compatibility claim is made.
- Codex SDK — local programmatic agent control
- Codex app-server — protocol and experimental transport limits
- Node 24 — HTTP server request handling
- OWASP — REST security controls
- MDN — AbortController
The inspected owner runbooks support the architectural summary, not a public code sample or blanket capability claim. Private infrastructure paths, account IDs, real record IDs, credentials, raw conversations and customer information are deliberately excluded from this original lesson.