I have been following the TiyGate project closely, and our team is currently developing a project with a very similar vision called ferryllm.
It is exciting to see that TiyGate also leverages an Intermediate Representation (IR) approach, successfully reducing the complexity of multi-protocol translation from $N \times M$ to $N + M$. This aligns perfectly with the core design philosophy behind ferryllm.
However, we have taken slightly different paths when it comes to the concrete implementation of the codebase:
- TiyGate uses Logical Separation: A single
EndpointCodec (one comprehensive trait) encapsulates the entire inbound and outbound encoding/decoding logic.
- ferryllm uses Physical Separation: It completely decouples
entry (Client-to-IR) and adapter (IR-to-Provider) into distinct modules and single-direction traits.
To explore which model is better suited for long-term system evolution, or if there is a sweet spot between the two, I would love to open up a discussion here.
Comprehensive Comparison
| Dimension |
Physical Separation (ferryllm approach) |
Logical Separation (TiyGate current) |
| File Count |
2N (N protocols, independent entry/adapter) |
N (N protocols, single highly-cohesive file) |
| Module Boundaries |
Clear (strict separation of ingress/egress concerns) |
Blurred (both directions mixed within one type) |
| Trait Count |
2 single-direction traits |
1 bidirectional mega-trait |
| Registration Complexity |
Requires registering both entry and adapter |
Only requires a single codec registration |
| Code Reuse |
Needs explicit shared utility modules |
Natural reuse (shared type context) |
| Testing Granularity |
Fine-grained (unidirectional flows can be isolated) |
Coarse (tests must account for bidirectional logic) |
| Readability |
High (lower cognitive load, unidirectional focus) |
Lower (files grow significantly as protocols expand) |
| Maintainability |
Better when protocols differ drastically |
Better when protocols are highly similar |
| Extensibility |
More flexible (supports mix-and-match or single-direction) |
More compact (high protocol suite integrity) |
| Boilerplate |
High (more ceremony and setup code) |
Low (minimal overhead) |
Discussion & Potential Hybrid Approach
While physical separation provides robust compile-time boundaries and isolated testability, it introduces boilerplate and registration overhead. On the flip side, logical separation keeps things compact but couples inbound and outbound concerns too tightly.
Could there be a third way—a Hybrid Approach?
For example:
- Physical Separation at the Trait Level: Split the logic into two separate traits—
IngressCodec and EgressCodec—to guarantee compile-time boundaries and single-direction testing.
- Logical Cohesion at the Implementation Level: Allow the same struct (e.g.,
OpenAiCodec) to implement both traits within a single file. These can then be aggregated under a blanket EndpointCodec marker trait, preserving TiyGate's current elegant single-plugin registration mechanism (via inventory).
I would love to get your thoughts on the following:
- Has the current logical separation caused any maintenance pain points as protocols become more complex?
- Do we foresee scenarios where a protocol suite might only need a single direction (e.g., acting strictly as an ingress gateway without bridging to an underlying provider)?
- How do you view the evolution of this architecture going forward? Looking forward to the discussion!
I have been following the TiyGate project closely, and our team is currently developing a project with a very similar vision called ferryllm.
It is exciting to see that TiyGate also leverages an Intermediate Representation (IR) approach, successfully reducing the complexity of multi-protocol translation from$N \times M$ to $N + M$ . This aligns perfectly with the core design philosophy behind ferryllm.
However, we have taken slightly different paths when it comes to the concrete implementation of the codebase:
EndpointCodec(one comprehensive trait) encapsulates the entire inbound and outbound encoding/decoding logic.entry(Client-to-IR) andadapter(IR-to-Provider) into distinct modules and single-direction traits.To explore which model is better suited for long-term system evolution, or if there is a sweet spot between the two, I would love to open up a discussion here.
Comprehensive Comparison
Discussion & Potential Hybrid Approach
While physical separation provides robust compile-time boundaries and isolated testability, it introduces boilerplate and registration overhead. On the flip side, logical separation keeps things compact but couples inbound and outbound concerns too tightly.
Could there be a third way—a Hybrid Approach?
For example:
IngressCodecandEgressCodec—to guarantee compile-time boundaries and single-direction testing.OpenAiCodec) to implement both traits within a single file. These can then be aggregated under a blanketEndpointCodecmarker trait, preserving TiyGate's current elegant single-plugin registration mechanism (viainventory).I would love to get your thoughts on the following: