Skip to content

Proposal: Update CLI output to introduce Source/Destination concepts and improve knowledge transfer #167

@leggetter

Description

@leggetter

CLI Output Representation Options

This document shows different ways to represent the Source → Connection → Destination flow without explicitly labeling "Connection".

Current format example:

test-ctx-2025103020190191271
│  Requests to → https://hkdk.events/imfr27krfuwyj5
└─ Forwards to → http://localhost:3000/ (cli-test-ctx-2025103020190191271)

test-20251030201856801609
│  Requests to → https://hkdk.events/8sflhne0f3v7s0
└─ Forwards to → http://localhost:3000/ (cli-test-20251030201856801609)

test-ctx-20251030003302677021
│  Requests to → https://hkdk.events/99ur7d9lf540ef
└─ Forwards to → http://localhost:3000/ (cli-test-ctx-20251030003302677021)

test-20251030003257478025
│  Requests to → https://hkdk.events/ayw7nqpjbdfhqp
└─ Forwards to → http://localhost:3000/ (cli-test-20251030003257478025)

Honest Assessment of Current Format

Cognitive and Learning Perspective:

The current format attempts to use familiar, action-oriented language ("Requests to", "Forwards to") that might feel intuitive to someone who hasn't learned Hookdeck's architecture. This follows a common UX pattern: meet users where they are by describing what happens rather than introducing new concepts upfront.

This approach has both benefits and significant drawbacks:

Pros:

  • Immediately understandable actions: "Requests to" and "Forwards to" describe the data flow without requiring prior knowledge
  • Low barrier to entry: Users don't need to learn what a "Source" or "Destination" is to understand webhooks are being forwarded
  • Action-focused: Matches how users might think about their immediate goal ("I need to forward webhooks to my localhost")

Cons:

  • Hides the mental model: By avoiding Source/Destination/Connection terminology, it actually prevents users from building the mental model they need for more advanced usage
  • Creates a learning cliff: Users start with action-based thinking but will hit a wall when they encounter Sources, Destinations, and Connections in the dashboard, docs, or when scaling beyond one connection
  • Ambiguous entities: The name on the first line (e.g., "test-ctx-2025103020190191271") has no label—is it a Source? A Connection? A project name? This ambiguity creates confusion when users need to reference it
  • Misleading simplicity: It suggests the system is simpler than it is, which causes cognitive dissonance later when users discover there are actually three entities (Source, Connection, Destination) orchestrating this flow
  • Poor knowledge transfer: Users can't apply what they learn from the CLI output to other Hookdeck interfaces where proper terminology is used
  • Visual hierarchy issues: The tree structure suggests the first line is a parent entity, but "Requests to" on the second line breaks this expectation—requests come to the entity above, not from it
  • Inconsistent with platform: Dashboard, API, and docs all use Source/Destination terminology; CLI should be the first introduction to these concepts, not a separate vocabulary

The Core Problem:

The format optimizes for immediate comprehension at the expense of effective learning. It's like teaching someone to drive by only explaining the pedals without mentioning the engine, transmission, or how cars work. They can drive in simple scenarios, but they'll be lost when something goes wrong or they need to do anything advanced.

From a Learning Theory Perspective:

Humans learn best when new information connects to a clear mental model. The current format fails this because:

  1. It doesn't establish what the entities are (only what they do)
  2. It creates a temporary mental model ("webhooks flow from requests to forwards") that must be unlearned and replaced with the real model (Source → Connection → Destination)
  3. This cognitive restructuring is harder than learning the correct model from the start

Better Approach:

Introduce the Hookdeck mental model immediately but keep it simple. "Source: URL" is both clear about what it is (a Source entity) and actionable (here's the URL). Users learn the right vocabulary from day one, making every subsequent interaction with Hookdeck build on this foundation rather than requiring cognitive translation.

The slight increase in initial cognitive load (learning "Source" and "Destination") is vastly outweighed by the benefit of having a consistent, accurate mental model that transfers to every part of the platform.

The Immediate Comprehension vs. Effective Learning Spectrum

When designing user interfaces, there's a fundamental tension between making something immediately understandable and teaching concepts that enable long-term effectiveness:

Immediate Comprehension ←────────────────────────────────→ Effective Learning
(Action-based, familiar)                                  (Concept-based, transferable)

Example: "Forward webhooks"                              Example: "Sources route to Destinations"
         No terminology                                           Full mental model required
         Maximum accessibility                                    Platform-specific knowledge

The spectrum explained:

  • Left side (Immediate Comprehension):
    • Uses familiar, action-oriented language
    • Hides complexity and terminology
    • Users can "get started" without learning anything new
    • Example: "Forward webhooks to localhost"
  • Right side (Effective Learning):
    • Introduces platform-specific concepts and terminology
    • Teaches mental models that transfer across the platform
    • Requires upfront cognitive investment
    • Example: "Sources receive webhooks and Connections route them to Destinations"

Where CLI output should sit:

                        Immediate ←─────────────────→ Effective
Current CLI format:     █ (Too far left)
Option 1:                              █ (Recommended)
Full architecture:                                   █ (Too far right)

CLI SWEET SPOT:                  [─────█─────]
                           Balanced for tool users

The CLI is a technical tool used by developers who will inevitably need to understand Hookdeck's architecture. It should lean toward teaching the mental model while remaining immediately actionable.


Option 1: URL-first with entity labels

This format prioritizes the URLs while explicitly labeling entities. Combines URL prominence with clear mental model reinforcement.

Current format example converted:

Source: https://hkdk.events/imfr27krfuwyj5 (test-ctx-2025103020190191271)
  └─> Destination: http://localhost:3000/ (cli-test-ctx-2025103020190191271)

Source: https://hkdk.events/8sflhne0f3v7s0 (test-20251030201856801609)
  └─> Destination: http://localhost:3000/ (cli-test-20251030201856801609)

Source: https://hkdk.events/99ur7d9lf540ef (test-ctx-20251030003302677021)
  └─> Destination: http://localhost:3000/ (cli-test-ctx-20251030003302677021)

Source: https://hkdk.events/ayw7nqpjbdfhqp (test-20251030003257478025)
  └─> Destination: http://localhost:3000/ (cli-test-20251030003257478025)

Single connection:

Source: https://hkdk.events/src_{source_id} (test-webhooks)
  └─> Destination: http://localhost:3030/webhook (local-dev)

Multiple connections from same source:

Source: https://hkdk.events/src_{source_id} (test-webhooks)
  ├─> Destination: http://localhost:3030/webhook (local-dev)
  └─> Destination: https://staging.example.com/webhook (staging)

Multiple sources:

Source: https://hkdk.events/src_{source_id_1} (test-webhooks)
  └─> Destination: http://localhost:3030/webhook (local-dev)

Source: https://hkdk.events/src_{source_id_2} (stripe-events)
  └─> Destination: http://localhost:3030/stripe (local-dev)

Benefits:

  • URLs are immediately scannable and copyable (right after the label)
  • Easy to reference: "Copy the Source URL" - scan for "Source:", copy the URL
  • "Copy the Destination URL" - scan for "Destination:", copy the URL
  • Entity labels explicitly reinforce Source/Destination mental model
  • Name context in parentheses provides additional clarity
  • Maintains Source → Destination visual hierarchy

Option 2: Name-first with entity labels

Current format example converted:

Source: test-ctx-2025103020190191271 → https://hkdk.events/imfr27krfuwyj5
  └─> Destination: cli-test-ctx-2025103020190191271 → http://localhost:3000/

Source: test-20251030201856801609 → https://hkdk.events/8sflhne0f3v7s0
  └─> Destination: cli-test-20251030201856801609 → http://localhost:3000/

Source: test-ctx-20251030003302677021 → https://hkdk.events/99ur7d9lf540ef
  └─> Destination: cli-test-ctx-20251030003302677021 → http://localhost:3000/

Source: test-20251030003257478025 → https://hkdk.events/ayw7nqpjbdfhqp
  └─> Destination: cli-test-20251030003257478025 → http://localhost:3000/

Single connection:

Source: test-webhooks → https://hkdk.events/src_{source_id}
  └─> Destination: local-dev → http://localhost:3030/webhook

Multiple connections from same source:

Source: test-webhooks → https://hkdk.events/src_{source_id}
  ├─> Destination: local-dev → http://localhost:3030/webhook
  └─> Destination: staging → https://staging.example.com/webhook

Multiple sources:

Source: test-webhooks → https://hkdk.events/src_{source_id_1}
  └─> Destination: local-dev → http://localhost:3030/webhook

Source: stripe-events → https://hkdk.events/src_{source_id_2}
  └─> Destination: local-dev → http://localhost:3030/stripe

Option 3: Pipe/flow character

Single connection:

Source: test-webhooks → https://hkdk.events/src_{source_id}
  │
  └─ Destination: local-dev → http://localhost:3030/webhook

Multiple connections from same source:

Source: test-webhooks → https://hkdk.events/src_{source_id}
  │
  ├─ Destination: local-dev → http://localhost:3030/webhook
  └─ Destination: staging → https://staging.example.com/webhook

Multiple sources:

Source: test-webhooks → https://hkdk.events/src_{source_id_1}
  │
  └─ Destination: local-dev → http://localhost:3030/webhook

Source: stripe-events → https://hkdk.events/src_{source_id_2}
  │
  └─ Destination: local-dev → http://localhost:3030/stripe

Option 4: Simplified with routing symbol

Single connection:

Source: test-webhooks → https://hkdk.events/src_{source_id}
  ↓
  Destination: local-dev → http://localhost:3030/webhook

Multiple connections from same source:

Source: test-webhooks → https://hkdk.events/src_{source_id}
  ├─ Destination: local-dev → http://localhost:3030/webhook
  └─ Destination: staging → https://staging.example.com/webhook

Multiple sources:

Source: test-webhooks → https://hkdk.events/src_{source_id_1}
  ↓
  Destination: local-dev → http://localhost:3030/webhook

Source: stripe-events → https://hkdk.events/src_{source_id_2}
  ↓
  Destination: local-dev → http://localhost:3030/stripe

Option 5: Connection name only (implicit Connection label)

Single connection:

Source: test-webhooks → https://hkdk.events/src_{source_id}
  └─ test-webhooks → local-dev
       └─ Destination: local-dev → http://localhost:3030/webhook

Multiple connections from same source:

Source: test-webhooks → https://hkdk.events/src_{source_id}
  ├─ test-webhooks → local-dev
  │    └─ Destination: local-dev → http://localhost:3030/webhook
  └─ test-webhooks → staging
       └─ Destination: staging → https://staging.example.com/webhook

Multiple sources:

Source: test-webhooks → https://hkdk.events/src_{source_id_1}
  └─ test-webhooks → local-dev
       └─ Destination: local-dev → http://localhost:3030/webhook

Source: stripe-events → https://hkdk.events/src_{source_id_2}
  └─ stripe-events → local-dev
       └─ Destination: local-dev → http://localhost:3030/stripe

Option 6: Simplified hierarchy (no "Destination" label)

Single connection:

Source: test-webhooks → https://hkdk.events/src_{source_id}
  └─> local-dev → http://localhost:3030/webhook

Multiple connections from same source:

Source: test-webhooks → https://hkdk.events/src_{source_id}
  ├─> local-dev → http://localhost:3030/webhook
  └─> staging → https://staging.example.com/webhook

Multiple sources:

Source: test-webhooks → https://hkdk.events/src_{source_id_1}
  └─> local-dev → http://localhost:3030/webhook

Source: stripe-events → https://hkdk.events/src_{source_id_2}
  └─> local-dev → http://localhost:3030/stripe

Evaluation Comparison

Each option is rated against the key criteria (1-5 scale, where 5 is best):

Option Easy to Reference Scannable Mental Model Context Preserved Scales Naturally Total Notes
Current 1/5 2/5 2/5 3/5 4/5 12/25 "Copy the URL next to 'Requests to'" - unclear, verbose; no entity labels
Option 1 5/5 5/5 5/5 5/5 5/5 25/25 Entity labels + URL prominence; "Copy the Source URL" scans for "Source:" label
Option 2 3/5 3/5 5/5 5/5 5/5 21/25 Good structure but requires "Copy the URL after 'Source:'"
Option 3 3/5 2/5 4/5 5/5 4/5 18/25 Pipe character adds visual noise; URLs not prominent
Option 4 3/5 3/5 4/5 5/5 3/5 18/25 Inconsistent (↓ for single, tree for multiple); same reference issue as Option 2
Option 5 2/5 2/5 5/5 5/5 5/5 19/25 Most explicit mental model but adds extra hierarchy layer; URLs buried deeper
Option 6 3/5 4/5 4/5 3/5 5/5 19/25 Cleaner but loses "Destination" context; still requires "after Source:" reference

Detailed Ratings

Current Format

test-ctx-2025103020190191271
│  Requests to → https://hkdk.events/imfr27krfuwyj5
└─ Forwards to → http://localhost:3000/ (cli-test-ctx-2025103020190191271)
  • Easy to Reference (1/5): Must say "Copy the URL next to 'Requests to'" - very unclear what "Source URL" means in this format
  • Scannable (2/5): Source name prominent but URLs secondary; "Requests to →" adds noise
  • Mental Model (2/5): No Source/Destination labels; doesn't reinforce the mental model; "Requests to" and "Forwards to" are actions, not entities
  • Context Preserved (3/5): Shows names but lacks entity type clarity (is the name a Source or Connection?)
  • Scales Naturally (4/5): Tree structure works but entity relationships unclear with multiple connections

Option 1: URL-first with entity labels

  • Easy to Reference (5/5): "Copy the Source URL" - scan for "Source:", URL immediately follows; explicit label makes reference unambiguous
  • Scannable (5/5): URLs prominent (right after short label); "Source:" and "Destination:" labels are scannable landmarks
  • Mental Model (5/5): Explicitly reinforces Source/Destination entities; hierarchy shows flow; best of both worlds
  • Context Preserved (5/5): Entity labels + names in parentheses provide complete context; nothing is ambiguous
  • Scales Naturally (5/5): Tree structure scales perfectly; entity labels remain clear with multiple connections

Option 2: Name-first with entity labels

  • Easy to Reference (3/5): Must say "Copy the URL after 'Source:'" - requires describing location
  • Scannable (3/5): URLs present but secondary to labels; eyes scan labels first
  • Mental Model (5/5): Explicitly shows Source → Connection → Destination with clear hierarchy
  • Context Preserved (5/5): All entity names clearly labeled
  • Scales Naturally (5/5): Tree structure scales perfectly to multiple connections/sources

Option 3: Pipe/flow character

  • Easy to Reference (3/5): Same issue as Option 2; pipe adds no referencing benefit
  • Scannable (2/5): Extra pipe line reduces density; URLs not prominent
  • Mental Model (4/5): Shows flow but pipe feels redundant with tree structure
  • Context Preserved (5/5): All entity names clearly labeled
  • Scales Naturally (4/5): Works but pipe line awkward with multiple connections

Option 4: Simplified with routing symbol

  • Easy to Reference (3/5): Same reference issue as Option 2
  • Scannable (3/5): Similar to Option 2; ↓ adds visual interest but no scan benefit
  • Mental Model (4/5): Shows flow but inconsistent (↓ vs tree structure)
  • Context Preserved (5/5): All entity names clearly labeled
  • Scales Naturally (3/5): Inconsistent approach (↓ for single, tree for multiple)

Option 5: Connection name only

  • Easy to Reference (2/5): URLs buried on third level; most complex reference path
  • Scannable (2/5): Three-level hierarchy makes scanning harder; URLs least prominent
  • Mental Model (5/5): Most complete representation of Source → Connection → Destination
  • Context Preserved (5/5): Shows all three entities explicitly with full context
  • Scales Naturally (5/5): Perfect hierarchical scaling for complex scenarios

Option 6: Simplified hierarchy

  • Easy to Reference (3/5): Same "after Source:" reference issue
  • Scannable (4/5): Cleaner than labeled versions; less text to parse
  • Mental Model (4/5): Shows Source → Destination but Connection is implicit
  • Context Preserved (3/5): Loses "Destination" label; destination names lack context
  • Scales Naturally (5/5): Clean tree structure scales well

Recommendation

Option 1 (URL-first with entity labels) scores highest (25/25) and directly solves the core usability issue: making URLs easy to reference while reinforcing the mental model. The format "Source: URL (name)" means when you say "Copy the Source URL", users scan for "Source:", see the URL immediately after, and understand they're copying from the Source entity. It combines the discoverability of explicit labels with the prominence of URL-first design.


Appendix: Introducing the Connection Concept

The Challenge

The winning Option 1 format successfully introduces Source and Destination entities, but the Connection—a core part of the Hookdeck mental model—remains implicit. This works well for single connections, but creates ambiguity with multiple connections from the same Source:

Source: https://hkdk.events/src_{source_id} (test-webhooks)
  ├─> Destination: http://localhost:3030/webhook (local-dev)
  └─> Destination: https://staging.example.com/webhook (staging)

The question: What creates these two separate routes? The answer is two different Connections, but this isn't visible in the output.

Why This Matters

Understanding Connections is crucial because they:

  • Control routing rules, transformations, and retry logic independently
  • Can be paused, deleted, or configured separately
  • Are the primary control point in Hookdeck's architecture
  • Are referenced throughout the dashboard and API

Users need to grasp that test-webhooks → local-dev and test-webhooks → staging are separate Connections, not just "outputs" of the Source.

Exploration: Adding Connection Visibility

Approach A: Minimal Connection Hint

Use connection names in the tree structure without adding "Connection:" label:

Source: https://hkdk.events/src_{source_id} (test-webhooks)
  ├─ test-webhooks → local-dev
  │    └─> Destination: http://localhost:3030/webhook (local-dev)
  └─ test-webhooks → staging
       └─> Destination: https://staging.example.com/webhook (staging)

Pros:

  • Shows the Source → Destination mapping that defines each Connection
  • Natural hierarchy: Source contains Connections, Connections route to Destinations
  • Connection becomes visible as the relationship between entities

Cons:

  • Adds visual complexity
  • Connection concept still implicit (no "Connection:" label)
  • Requires understanding that "Source → Destination" represents a Connection

Approach B: Explicit Connection Labels

Make Connections first-class in the representation:

Source: https://hkdk.events/src_{source_id} (test-webhooks)
  ├─ Connection: test-webhooks → local-dev
  │    └─> Destination: http://localhost:3030/webhook (local-dev)
  └─ Connection: test-webhooks → staging
       └─> Destination: https://staging.example.com/webhook (staging)

Pros:

  • Explicitly teaches all three entities: Source, Connection, Destination
  • Complete mental model from day one
  • Accurate representation of Hookdeck's architecture
  • Users immediately understand they can control Connections independently

Cons:

  • More verbose for single-connection scenarios (most common use case)
  • Adds another level of hierarchy
  • May feel like "information overload" initially

Approach C: Connection Annotations

Keep the simple format but add contextual information:

Source: https://hkdk.events/src_{source_id} (test-webhooks)
  ├─> Destination: http://localhost:3030/webhook (local-dev) [connection: test-webhooks → local-dev]
  └─> Destination: https://staging.example.com/webhook (staging) [connection: test-webhooks → staging]

Pros:

  • Maintains visual simplicity of Option 1
  • Introduces Connection concept without dominating the output
  • Easy to ignore until users need it

Cons:

  • Connection feels secondary/optional
  • Harder to scan (important info at the end of line)
  • Doesn't show hierarchical relationship clearly

Approach D: Progressive Disclosure

Use simple format for single connection, reveal Connections when multiple exist:

Single connection:

Source: https://hkdk.events/src_{source_id} (test-webhooks)
  └─> Destination: http://localhost:3030/webhook (local-dev)

Multiple connections (show Connection layer):

Source: https://hkdk.events/src_{source_id} (test-webhooks)
  ├─ Connection: test-webhooks → local-dev
  │    └─> Destination: http://localhost:3030/webhook (local-dev)
  └─ Connection: test-webhooks → staging
       └─> Destination: https://staging.example.com/webhook (staging)

Pros:

  • Don't pay complexity cost until it's needed
  • Teaches Connection concept when it becomes relevant (multiple connections)
  • Natural discovery: "Oh, when I have multiple destinations, those are called Connections"

Cons:

  • Inconsistent representation (format changes based on count)
  • May confuse users: "Why does it look different now?"
  • Users with single connection never learn about Connections

Recommendation

Approach B (Explicit Connection Labels) is the most honest approach because:

  1. Consistent mental model: Works the same whether you have one connection or ten
  2. Complete education: Users learn all three entities from the start
  3. Accurate architecture: Represents how Hookdeck actually works
  4. Supports growth: When users need to configure a Connection, they already know what it is

The verbosity concern is actually a feature, not a bug. For a single connection:

Source: https://hkdk.events/src_{source_id} (test-webhooks)
  └─ Connection: test-webhooks → local-dev
       └─> Destination: http://localhost:3030/webhook (local-dev)

This looks "too complex" at first glance, but it:

  • Shows the complete picture immediately
  • Makes it obvious that Connections are configurable entities
  • Prepares users for the dashboard where Connections are the primary control surface
  • Takes only seconds more to parse than the simpler version

Alternative: Start with Option 1 (implicit Connections) but when a user creates multiple connections, show a one-time educational message:

Source: https://hkdk.events/src_{source_id} (test-webhooks)
  ├─> Destination: http://localhost:3030/webhook (local-dev)
  └─> Destination: https://staging.example.com/webhook (staging)

💡 These two routes are separate Connections in Hookdeck. Each Connection can be
   configured, paused, or deleted independently via the dashboard.

Appendix B: Applying the Spectrum to Quickstart Documentation

Where should a Quickstart sit on the spectrum?

                        Immediate ←─────────────────→ Effective
Current CLI format:     █ (Too far left)
Option 1:                              █ (Recommended)
Full architecture:                                   █ (Too far right)

QUICKSTART SWEET SPOT:           [─────█─────]
                              Balanced position

The Quickstart Position

Quickstart documentation sits at a critical point in the user journey—it's often the first hands-on experience with the platform. This position should:

  1. Introduce core terminology (Source, Destination) but keep it minimal
  2. Use the real mental model but present it simply
  3. Make actions immediately possible while teaching concepts
  4. Enable knowledge transfer to dashboard, API, docs without requiring translation

Why the current CLI format is too far left for quickstarts:

  • ✗ Uses temporary vocabulary ("Requests to", "Forwards to") that must be unlearned
  • ✗ Doesn't prepare users for any other Hookdeck interface
  • ✗ Creates cognitive dissonance when users encounter Sources/Destinations elsewhere
  • ✗ Optimizes for the first 30 seconds at the expense of the next 30 minutes

Why Option 1 hits the quickstart sweet spot:

  • ✓ Introduces real concepts (Source, Destination) immediately
  • ✓ Still action-oriented (URLs are prominent and copyable)
  • ✓ Small cognitive investment (learning 2 terms) with massive long-term payoff
  • ✓ Every subsequent Hookdeck interaction reinforces rather than contradicts this model
  • ✓ Users can say "Copy the Source URL" and it's unambiguous

Why explicit Connections might be too far right for quickstarts:

  • ? Adds a third concept immediately (Source, Connection, Destination)
  • ? Creates visual complexity that may intimidate in initial experience
  • ? Could be introduced progressively (quickstart → dashboard → advanced docs)

The Minimum Viable Mental Model

A quickstart should find the minimum viable mental model—the smallest set of concepts that:

  1. Are immediately usable (you can complete the quickstart task)
  2. Transfer to advanced usage (you don't need to relearn later)
  3. Scale naturally (adding complexity builds on rather than replaces this foundation)

For Hookdeck quickstarts, that minimum viable mental model is Source → Destination, with Connections introduced when users need multiple routes or advanced configuration.

This provides progressive disclosure while maintaining visual simplicity, letting users build their mental model gradually while keeping the CLI output scannable.

Option 2 is a solid second choice (21/25) with the same entity labels but places the name before the URL, making the URL slightly less prominent and scannable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions