Project · VDX riazrahaman.comHome →

Not one giant
trip robot.
A box of bricks.

VDX proposes building agentic systems as a library of small, typed capabilities — search flights, rank them, find a hotel, reserve a table — and an intent engine that assembles only the pieces your actual request needs. Ask for flights, and the hotel machinery never runs. 🧱

What this page covers → the idea, the bricks, how the builder composes them, the typed handoffs, the approval gates, and the five scenarios.
Status → illustrative reference · every provider and price is mock · nothing real is booked
Domain → travel as the worked example · the model is domain-agnostic
Edition → October 2026 · v0.1.0
Interactive

Ask VDX Anything 💬

Ask questions about VDX architecture, bricks, recipe composition, and gates. Answers are generated by hermes3:8b running on Riaz's local workstation via a secure tunnel.

Prologue

The engine plans. Nobody else over-plans. 🧭

The obvious way to build a travel assistant is one fixed checklist: flights, hotel, restaurants, activities — every time, even when you only wanted flights. VDX never builds that recipe. It keeps a library of independent capabilities and lets an intent engine compose the smallest valid graph that satisfies your stated outcome.

🗣️
You

State an outcome

“Flights Dubai to Paris on November 12. Nothing else.” The “nothing else” is a first-class input — explicit exclusions shape the plan as much as requests.

🧩
The intent engine

Composes and validates

Works backwards from what you asked for to the capabilities that can provide it, snaps their typed outputs to inputs, and proves the plan is legal before anything runs.

🔌
The adapters

Touch the real world

Typed plugs behind stable interfaces: a flight API, a hotel API, a browser acting for you. Reads run under permissions; writes stop at an approval gate.

Why this constraint is the design. Everything in the project descends from one rule: only verified outcomes count as completion. A tool call that returned 200 is not a ticket. That is why every artifact is machine-checkable, why booking sits behind an explicit approval, and why an API timeout after submitting a payment gets its own state instead of being guessed into success.
Chapter 01

Small bricks, exact labels 🧱

Each capability does one job, declares what it gives and needs in versioned types, and names the adapter that makes it real. Six ship in this reference set — all mock-backed. The full catalog sketches ~40 more across route, flights, event, stay, dining, entry, payment and coordination.

route.resolve

Can this trip even go by air? Resolves origin/destination into a route plus transport feasibility.

read-onlymock adapter
flight.search

Requires origin, destination, departure date. Produces flight.options for ranking.

read-onlyTTL 300s
flight.rank

Orders raw options by constraints first, then soft preferences like cabin class.

read-onlypure
hotel.search

Needs a place and dates; a conference venue improves ranking — but is never assumed.

read-onlyparallel-safe
restaurant.search

Availability near a point for a party size and time — bookability, not just listings.

read-onlystarter schema
conference.context

Resolves an event into dates and venue with provenance — missing dates force a clarification.

read-onlycontext source
flight.purchase not in sample

The write-side brick: separately registered, requires a revalidated offer and an approval token — an offer quote is not a ticket.

side effect: writeapproval-gated
Field on every brickWhat it tells the engine
provides / requiresThe typed outputs it hands over and typed inputs it needs — bricks only fit when the types match
optional inputsPreferences that improve results but must never be inferred into existence (cabin class, max price)
preconditions & permissionsEligibility rules and the least-privilege scopes an execution requires
side effectread_only vs write — writes get all the ceremony in Chapter 05
output_ttl_secondsHow long a result stays trustworthy before it must be revalidated
execution & adapterTimeout, bounded-exponential retry, and the allowlisted adapter implementation
Chapter 02

One brick is one small file 📇

A capability's contract is a recipe.yaml manifest plus versioned JSON schemas for its input and output. The YAML is data to review, never code to run — the registry normalizes it to canonical JSON and validates it before any adapter is loaded.

# travel.flight.search @ 1.0.0
id: travel.flight.search
version: 1.0.0
kind: atomic
provides: [flight.options]
requires: [origin, destination,
           departure_date]
optional: [preferences,
           constraints]
dependencies: [travel.route.resolve]
side_effects: none
permissions: [travel.read]
adapter: "mock:travel.flight.search"
input_schema:  schemas/flight-search.input.schema.json
output_schema: schemas/flight-search.output.schema.json
timeout_ms: 15000
# what the engine reads out of it

Gives: a set of flight options

Needs: where from, where to,
       a departure date

Nice to have: cabin, budget, airlines —
  but the engine must not invent them

Wants first: route.resolve ran
  (don't search for an impossible route)

Touches nothing: pure lookup

Trusts: only the allowlisted mock adapter
  — manifests can't smuggle instructions
Versioned types are the mortar. Free-form agent prose is not an acceptable handoff between bricks. Every artifact — RouteResolution.v1, FlightOptionSet.v1, RankedFlightOptions.v1 — carries its schema version, provenance, creation time and expiry, so the engine can prove two bricks fit before it lets them run, and can tell a stale result from a fresh one.
Chapter 03

From a sentence to a legal plan 🧩

Everything left of execution is deterministic. An LLM may propose modules; validation must approve the graph — types, cycles, permissions and side effects — before a single node runs. Selection states matter: a brick being available is never a reason it was selected.

TRUSTED · VERSIONED REGISTRY · 6 BRICKS + ~40 in catalog User request Intent & scope Context & constraints Capability discovery Planner · builds DAG Deterministic validation Scheduler Approval gate Adapters Outcome verification Result & state provides new information · failure replan affected nodes only
The left column is the engine's deterministic spine; the approval gate only exists for bricks with side effects. The hot path back up is replanning: new information invalidates affected nodes and the loop reruns — nothing else.

↔ scroll the diagram sideways

goals     = extract_goals_and_scope(intent)          # outcomes + explicit exclusions
facts     = resolve_authorized_context(context)      # provenance & freshness tracked
candidates = registry.find_providers_for(goals.outputs)
eligible  = policy_and_precondition_filter(candidates, facts)
graph     = backward_chain_dependencies(eligible, facts)   # typed outputs → required inputs
graph     = remove_unneeded_and_excluded_nodes(graph, goals) # "that's all" cuts here
graph     = resolve_alternatives_and_conflicts(graph)
if graph.missing_critical_inputs: request_minimal_clarification()  # ask, never invent
validate_types_cycles_permissions_effects(graph)
return graph.with_approval_gates_and_provenance()
requiredconditionaloptional excludedblockeddeferred
Clarification beats invention. If a critical date or party size is genuinely unknown, the engine asks one focused question instead of guessing. An invented conference date poisons every dependent node downstream of it.
Constraints rank harder than wishes. A hard arrival deadline — be at the keynote — can never be traded away for a cheaper fare. A preferred cabin is a soft preference the ranker may trade; hard budget caps override soft preferences, always.
Chapter 04

Artifacts, not prose 🔗

The flight pipeline reads like an assembly line because each stage's output is a versioned artifact the next stage's input schema can check — each carrying provenance, creation time, correlation ID and expiry. And every step has a state the engine can reason about.

RouteResolution.v1→ FlightSearchRequest.v1→ FlightOptionSet.v1→ RankedFlightOptions.v1→ SelectedOffer.v1→ RevalidatedOffer.v1→ ApprovalToken.v1→ TicketingResult.v1→ VerifiedTicket.v1
DISCOVERED→ELIGIBLE→PLANNED→READY→RUNNING→VERIFYING→SUCCEEDED
WAITING_FOR_INPUTWAITING_FOR_APPROVALBLOCKED FAILEDINDETERMINATECANCELLED

Read-only branches with independent inputs run concurrently — hotel search does not wait for flight ranking. Device actions (a browser clicking through a provider) get the same skepticism as APIs: a successful click is evidence, not proof.

Chapter 05

Search is free. Buying is not. 🚦

Every read-only brick runs under permission scopes without ceremony. The moment a brick can change the real world — purchase, reserve, cancel, pay — it is a different species: separately registered, explicitly authorized, idempotent, audited, and verified against the provider.

  1. Explicit approval — no purchase, reservation or cancellation happens without a required ApprovalToken granted for exactly that action.
  2. Revalidation before commitment — the offer is revalidated at the moment of purchase; a quoted fare that went stale is not a ticket waiting to be claimed.
  3. Idempotency keys — where providers support them, retries cannot double-charge; where they don't, the outcome is reconciled, not assumed.
  4. Verified completion — the executor marks success only after independently confirming the ticket or confirmation exists.
The state that keeps people honest: INDETERMINATE. A booking API times out after submitting — did it charge you? Nobody knows yet, and pretending is how double charges and phantom tickets happen. The engine reconciles with the provider before retrying, and never auto-cancels or auto-repurchases an existing ticket: amendments are proposed, then authorized.
The LLM proposes; determinism disposes. Injected provider text cannot add forbidden modules or bypass approvals — manifests are inert data, adapter IDs are allowlisted, and a deterministic validator owns the final gate. Acceptance test 11 fails any engine where a clever prompt buys itself a plane ticket.
Minimal data, scoped permissions. User data stays small and permission-scoped; the friend's neighborhood is shareable for commute context — the friend's street address is not, and is never requested by default.
Chapter 06

Five phrases, five graphs 🧭

The same brick library, composed differently by what you actually said. Notice what is absent in each — absence is the whole point.

“Show me flights Dubai to Paris on November 12. Nothing else.”

Flights only

route.resolve → flight.search → flight.rank → options.present

Not selected: hotels, restaurants, activities, ground transport, booking.
“Conference in Paris Monday morning. Flights from Dubai and a hotel near the venue.”

Conference + hotel

conference.context → arrival deadline → flight.search
venue → hotel.search near venue → cross-check dates → present

In parallel: flight and hotel branches run concurrently once their inputs are known.
“Same conference — but I'm staying with a friend.”

Friend's place

flight branch unchanged · hotel branch never composed

Privacy default: friend's neighborhood only if commute planning needs it; exact address never requested.
“Reserve dinner for two near the venue Tuesday at 8.”

Dinner only

venue.resolve → restaurants.discover → availability → select → confirm → reserve → verify

Not selected: the entire flight and hotel machinery. Separate intent, separate graph.
“Actually the keynote starts at 8 AM, not 10.”

Mid-plan change

invalidate arrival feasibility + rankings → recompute affected nodes only

Preserved: unrelated confirmed artifacts. Existing tickets are never auto-cancelled.
{
  "plan_id": "plan_123",
  "intent": "travel.conference_trip",
  "scope": ["flights", "hotel"],
  "excluded": ["activities", "restaurants"],
  "nodes": [
    { "id": "event",   "capability": "event.resolve",       "depends_on": [] },
    { "id": "route",   "capability": "route.resolve",       "depends_on": [] },
    { "id": "flights", "capability": "flights.search",     "depends_on": ["event", "route"] },
    { "id": "hotels",  "capability": "hotels.search",      "depends_on": ["venue"] },
    { "id": "review",  "capability": "plan.present",       "depends_on": ["flights", "hotels"] }
  ],
  "approval_gates": ["before_purchase"],
  "status": "planned"
}
Chapter 07

In the box — and on the roadmap 📦

An illustrative reference, deliberately mock end-to-end: the contracts and the test list are real, the inventory is not. The repo pairs this page with the full engineering handover and a plain-language explainer.

6capability manifests in the sample
12versioned JSON schemas
8example intents, plans & patches
~40sketched capabilities in the catalog
10acceptance tests to pass
0real bookings — all mocks
Path in the repoWhat lives there
docs/01-eli5-overview.mdThe whole model in plain language — the LEGO framing this page follows
docs/02-architecture.mdEngineering handover: composition algorithm, execution states, module map, acceptance tests
docs/03-capability-contracts.mdFile formats, composition rules, security and submission requirements
capabilities/ · schemas/The six sample manifests and their typed input/output contracts
examples/Intents, composed DAG plans, a mock adapter response, a stay-change patch
tests/ · SUBMISSION_CHECKLIST.mdWhat a compliant engine must pass, and what a team submission must include

Four phases before this touches a real airline

  1. Contracts — finalize the manifest schema, typed artifacts, selection states, side-effect taxonomy and approval contract; implement five read-only travel capabilities.
  2. Planner — backward chaining, dependency DAG, scope exclusions, hard/soft constraints, explainable selection; test flight-only vs. conference vs. friend scenarios.
  3. Runtime — scheduler, adapters, event store, verification, bounded retries, reconciliation, idempotency.
  4. Extensions — hotels, dining, calendar, device execution, composite templates; measured on task completion, excess invocations, clarification burden, cost and verified success rate.
The instruction to the team, verbatim: do not build one recipe for “plan a trip.” Build a library of small, typed, independently testable capabilities. Let the engine discover and compose only what the user's specific goal requires — and require authorization and verification for consequential actions.