Skip to content

shell: builtins vs. core API #9002

@shykes

Description

@shykes

Context

The shell introduces a new concept of builtins (.help, .login etc). Builtins can be contextually in a pipeline (for example .container | from alpine | .doc) which makes them very useful.

Problem

The relationship between shell builtins and core API is unclear: some builtins map directly to core API calls, others don't.

This creates the risk of a "shadow API". We should clarify the relationship that we want.

Solution

A solution is still being discussed. Please participate below.

Initial thoughts from @sipsma, on the possibility of builtins becoming a shadow API:

my main thought is that it would be better to avoid too much of that since, all else being equal, it's better to have functionality in the core API. Then it's available to e.g. module function implementations too (which use the various SDKs directly and don't go through dagger shell)

However, for functionality that absolutely only ever makes sense in the context of dagger shell, then it should be fine. So I guess that raises the question what sort of builtins you are thinking about specifically here

Initial thoughts from @shykes:

Empirically, when I'm tempted to add a builtin today, it's for one of the following reasons:

  1. It involves accessing the client context (filesystem; env variables; commands; network) and therefore feels "weird and special" - stuff like Directory.export, Service.up, etc. It's part of the Dagger API today, but it's a special and weird part. So moving it out can be tempting.
  2. It's "middleware" - a cross-cutting action that I want to inject into any type. For example .doc. I can't just add a doc function to every single type - it wouldn't belong there. It would require adding a new dimension to the schema.
  3. It's faster to iterate. Sometimes I want to add polish on an existing call. Or try a new syntax for doing the same thing. Or add a bunch of small but useful calls. I feel a freedom and a velocity adding builtins to the shell, that I just don't know how to get when contributing to the core API. There's the complexity of the code; the overhead of building and testing; the bikeshedding and having to argue with lots of people; the concerns about breaking changes; etc. Below a certain size of change, I won't even bother with the overhead.
  4. The API got bloated. In the early days we carefully bikeshedded every detail of the API, with the assumption that it was user-facing. Over time we started treating it more like a hidden implementation detail. As a result, we can't just expose the core API as-is as shell builtins. It's too bloated. So no matter what, some hiding has to happen. Then from there, it's a slippery slope. It used to be the API itself was treated like a self-sufficient UX domain - you designed it end-to-end so that interacting with it would make sense. Now that it's not the case, I kind of need a another self-sufficient UX domain.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions