Metacello Scripting API (strawman)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Metacello Scripting API (strawman)

Dale Henrichs
To start with we'd basically like to replace the following expressions for loading a Metacello
project:

  Gofer new
    squeaksource: 'MetacelloRepositorty';
    package: 'ConfigurationOfSeaside30';
    load.
  ((Smalltalk at: #ConfigurationOfSeaside30) version: '3.0.6') load: #('Base').

with something like the following:

  Metacello new
    project: 'Seaside30';
    squeaksource: 'MetacelloRepository';
    version: '3.0.6;
    load: #('Base').

If you're familiar with GoferProjectLoader, you'll see that I'm not quite following their API, but
I have my reasons which should become apparent as I move forward.

I think that the above Metacello-expression nicely replaces the Gofer-expression, but by eliminating
Gofer from the equation we have lost the ability to simply load the configuration package itself,
but that's easily addressed by adding a #get command:

  Metacello new
    project: 'Seaside30';
    squeaksource: 'MetacelloRepository';
    get.

which just loads the ConfigurationOfSeaside30 package from the 'http://www.squeaksource.com/MetacelloRepository'
repository.

Before moving on I would like to mention that I can imagine a case where the following expression
would be useful (no repository specification):

  Metacello new
    project: 'Seaside30';
    get.

I suggest that when the repository is not included then a platform-specific search order be
used ... This would be one of the places where Pharo or Squeak could introduce the notion of a set of
platform-approved repositories.

In a similar vein, I also would like to include the following:

  Metacello new
    project: 'Seaside30';
    signature: 'dkh.375';
    get.

Which would load an explicit version 'ConfigurationOfSeaside30-dkh.375' of the configuration package ... This would allow one to write something like the following:

  (Metacello new
    project: 'Seaside30';
    signature: 'dkh.375';
    version: '3.0.6';
    get)
      compare:
        (Metacello new
          project: 'Seaside30';
          signature: 'dkh.380';
          version: '3.0.6';
          get).

But I'm getting a bit ahead of myself... Getting back to the load operation:

  Metacello new
    project: 'Seaside30';
    squeaksource: 'MetacelloRepository';
    version: '3.0.6;
    load: #('Base').

I think that the #fetch and #record variants need to be included, so we should support the following:

  Metacello new
    project: 'Seaside30';
    squeaksource: 'MetacelloRepository';
    version: '3.0.6;
    fetch: #('Base').

  Metacello new
    project: 'Seaside30';
    squeaksource: 'MetacelloRepository';
    version: '3.0.6;
    record: #('Base').

So the API has STATE messages and ACTION messages. The STATE messages (project:, version:, squeaksource:, signature:, branch:, etc.) won't have interesting return values. You have to use one of the ACTION messages (get, load, load:, fetch, fetch:, record, record:, compare:, etc.) to have an interesting return value.

Since we're building a scripting API, it might be convenient to create a script that doesn't involve a ConfigurationOfXXX class being created. This API would be used for projects that involve one or two packages and maybe a project or two where the simplest script would be something like the following:

  Metacello new
    project: 'MyProject';
    for: #common
      do: [:spec |
        spec
          repository: 'http://www.squeaksource.com/MyProject';
          package: 'MyProject'. ];
    load.

So yes, this script boils down to a simple Gofer script that looks like the following:

  Gofer new
    url: 'http://www.squeaksource.com/MyProject';
    package: 'MyProject';
    load.

But you can't easily expand a Gofer script to make 'MyProject' dependent upon 'Seaside30':

  Metacello new
    project: 'MyProject';
    url: 'http://www.squeaksource.com/MyProject';
    for: #common
      do: [:spec |
        spec
          project: 'Seaside30' with: [
            spec
              version: '3.0.6';
              repository: 'http://www.squeaksource.com/MetacelloRepository'. ];
          package: 'MyProject' with: [ spec requires: 'Seaside30']. ];
    load.

and if you don't like the #for:do: style then perhaps something like the following from the MetacelloToolBox API:

  Metacello new
    project: 'MyProject';
    url: 'http://www.squeaksource.com/MyProject';
    for: #common;
    projects: {
          Metacecello new
            project: 'Seaside30';
            version:'3.0.6';
            url: 'http://www.squeaksource.com/MetacelloRepository'. };
    packages: #('MyProject');
    dependencies: {'MyProject' -> #('Seaside30')};
    load.

We can work through the details of the API later, the important point is that one can write a load script that includes package and project dependencies without ever having to create and save a ConfigurationOfMyProject class/package. Naturally, it is only a couple more steps to being able to create (create command creates the ConfigurationOf class) and save (commit: the ConfiguarionOfMyProject package to the MyProject repository) the configuration when the time is right:

  Metacello new
    project: 'MyProject';
    url: 'http://www.squeaksource.com/MyProject';
    version: '1.0';
    for: #common
      do: [:spec |
        spec
          project: 'Seaside30' with: [
            spec
              version: '3.0.6';
              repository: 'http://www.squeaksource.com/MetacelloRepository'. ];
          package: 'MyProject' with: [ spec requires: 'Seaside30']. ];
    create;
    save: 'Monticello commit comment'.

A similar style can be used to edit existing configurations programmatically as well...

Well I think that by now you get the basic idea ... upgrade, compare, list upgradable projects, etc. are some of the commands that would need to be added, but for those guys it is a matter of just adding/implementing the necessary commands ...

Oh, I almost forgot, but the basic mechanisms for doing all of the above already exist in Metacello. Between the MetacelloToolBox API and the version constructors all of these commands will be straightforward to implement, so I think that it will come down down to:

  a) deciding where the cutpoint for the API should be (i.e., just stick to loading)
  b) deciding between for:do: and MetacelloToolBox API ...

I'm somewhat partial to the for:do: style since it is consistent with the existing specification api for configurations, however, the MetacelloToolBox API style may easier for newcomers to grasp and may provide a bridge for newcomers that introduces folks to the for:do: style.

Anyway, I'm interested in hearing feedback ...

Dale
Reply | Threaded
Open this post in threaded view
|

Re: Metacello Scripting API (strawman)

Dale Henrichs
I'm still riffing on the API and it occurs to me that one could arrange to use the api for accessing specific components within a project.

Get an instance of MetacelloMCProject and return #latestVersion:

  (Metacello new
    project: 'Seaside30';
    squeaksource: 'MetacelloRepository';
    get) latestVersion.

Get an instance of MetacelloMCVersion and return the #author:

  (Metacello new
    project: 'Seaside30';
    squeaksource: 'MetacelloRepository';
    version: '3.0.6';
    get) author.

Get an instance of MetacelloVersionSpec for the #pharo section and return the package named 'Grease-Slime':

  (Metacello new
    project: 'Seaside30';
    squeaksource: 'MetacelloRepository';
    version: '3.0.6';
    section: #pharo;
    get) packageNamed: 'Seaside-Slime'.

Or get an instance of MetacelloVersionSpec to change the version for the 'Grease Slime' project:

  ((Metacello new
    project: 'Seaside30';
    squeaksource: 'MetacelloRepository';
    version: '3.0.6';
    section: #pharo;
    get)
      packageNamed: 'Grease Slime')
        versionString: '1.0.6.3'.

BTW, some of these things are easy to get in the existing API and some of these are hard to get (digging into sections takes a completely different path than accessing versions from the project) ... but this API could mask a lot of the complexity ...

Dale
Reply | Threaded
Open this post in threaded view
|

Re: Metacello Scripting API (strawman)

Dale Henrichs
In reply to this post by Dale Henrichs
Ben,

Thanks for feedback ... despite some differences in minor details, I think we're thinking along the same lines.

`Metacello new` vs `(Metacello project: 'MyProject')`

I suppose that ascetics are in the eyes of the beholder: use a class-side method requires parenthesis to use message cascading. In any case it's not necessary to enforce a convention. It is easy enough to have both class and instance side methods for #project: and support both scripting styles...

`get` vs `getConfiguration`

For a scripting API, I prefer short names over long names like: get, load, fetch, record.

`downloadComponents`

Later on in your post you asked what the `fetch` command was for ... the `fetch` command does exactly what you are suggesting for `downloadComponents` although you do need to specify a version so the usage of the `fetch` command would look like the following:

  Metacello new
    project: 'MyProject';
    version: '3.0.6';
    fetch.

`previewChanges`

The `record` command already does part of the work towards providing `preview` capabilities:

  (Metacello project: 'MyProject')
    version: '3.0.6';
    record.

returns a MetacelloLoadDirective that lists the packages that would be loaded if you did the `load`. If you print the result of the above expression you'd see the list of packages/projects that would be loaded, so it makes sense to add a `preview` command (short name) that opens up a view on the changes for each of the mcz files:

  Metacello new
    project: 'MyProject';
    version: '3.0.6';
    preview.

`browse`

In general I like the idea of supporting a browse command, however at the moment there really aren't any GUI tools for Metacello, as the tools do come online, then I think that a `browse` command is the way to go.

`squeaksource:`

I used `squeaksource:`, because Gofer (an scripting API for Monticello) has found it convenient to add the shortcut methods for some of the more popular repositories ... If you look closely at all of the examples, I kind of flip flopped around interchanging the use of `squeaksource:`, 'repository:` (as you suggest), and `url:` another message supported by Gofer.

I tend to feel that there should be a bit of compatibility between Gofer and Metacello (using `new` in scripts, supporting `squeaksource:`, `gemsource:`, `blueplane:`,etc.). Where common concepts are used there should be a common way of expressing them ...

`GoferProjectLoader features`

I think that there is value in the GoferProjectLoader features that manage a set of personal repositories and projects. The features that you mention do fall into the category of tools (for the most part) and I want to draw a line between support for tools and maintaining tools.

I tried to create a common set of GUI tools a year ago and eventually ran into issues that I could not resolve to my satisfaction. Additionally, I just don't have the time to commit to maintaining the core Metacello capabilities and a common set of cross-platform tools. There is a lot of effort involved in putting together a good tool set and I just don't have the time.

With that said, the MetacelloToolBox class was created to provide a common API for tool builders to use to provide services while ensuring common behavior across all tools for common operations.

The Metacello class is intended to provide a set of common commands that are of use to everyone and I would expect that folks building script-based tools will be able to extend the Metacello scripting API when it makes sense to do so ...

With that said, I do intend to look closely at the GoferProjectLoader features to see if some of the functionality could be shared across tools (searching through a list of repositories, comes immediately to mind).

`platform specific search`

With regards to my thinking about platform specific search, what I was thinking of there is that GemStone, Pharo, and Squeak platforms might want to have a different default set of repositories in which to look for projects, so I want to be able to support that capability (which would be somewhat independent of the GoferProjectLoader features.

'where does the output go'

The result of scripting commands are objects and in a scripting environment (meaning executed in a workspace) the printing or inspecting are the natural ways to view the results.

I will spend some time thinking about the fact that it would be natural to want to `browse` the results (i.e., bring up a tool designed to view the results), but I will need to think about what to do in the case of multiple tool providers being installed in the image at the same time ... The problem is analagous to determing whether or not you want the OB browser to be used or not ... I'm not aware of a clean solution to the problem, especially a cross-platform solution:)

`Configurationless loading`

You mention that I am 'quite keen on this' and you are right ... Some folks don't use Metacello because they think it is too cumbersome to create ConfigurationOfXXX class just for a couple of packages and to a certain extent they are right ...

So I imagine a continuum of scripting ... One starts with Gofer scripts (or Installer scripts in Squeak) and when one needs to include project dependencies, they graduate to simple Metacello scripts (with emphasis on simple:) that can be copied from a web-site or email message .... then once the project reaches the point where the script is no longer manageable or there is a need to manage multiple versions of the project, it seems a natural extension to be able to create a configuration from a Metacello script ...

I know for certain that supporting the basic project and version operations (get, load, fetch, record) with a common scripting API makes a lot of sense ...

The next tier of commands are closely related to the load operation and seem to make sense for scripting:

  - current version of project(s)
  - refresh current version or project(s)
  - upgrade project(s)

The next tier of potentially scriptable commands includes operations for saving your work and creating new versions like:

  - commit dirty mcz files, update configuration, commit configuration
  - create new version or baseline
  - simple edits to existing version or baseline

The above commands are definitely crossing the line into the realm of tools. Personally I don't like to commit anything without reviewing the changes that I've made which involves invoking GUI tools and I also know that there is some disagreement over the details of what exactly should be done when you commit a configuration ....

Another tier of commands would be support for 'configurationless loading'. The problem here appears to be that none of the suggestions I've made so far are very "clean" solutions ... the scripts so far look fairly clunky .... I asume that if we came up with a clean-looking solution then you'd not tell me:

  "Don't try to solve the world all at once."

I agree in principle ... a line must be drawn for the first cut of the API, but in my mind the place to draw the line is not completely clear ...

Of course I'm still waiting to hear from Colin and the Squeak folks. If the Metacello scripting API is not going to be included in the base images for all three platforms, then trying to define a common scripting API is a moot point...

Dale

----- Original Message -----
| From: "Ben Coman" <[hidden email]>
| To: "Dale Henrichs" <[hidden email]>
| Cc: [hidden email], "Stéphane Ducasse" <[hidden email]>, [hidden email], "Esteban
| Lorenzano" <[hidden email]>, "Mariano Martinez Peck" <[hidden email]>
| Sent: Saturday, January 28, 2012 4:04:32 AM
| Subject: Re: Metacello Scripting API (strawman)
|
| btw, my emails are bouncing from googlegroups, so you'll need to
| fwd/reply to this to capture it there...
|
| Dale Henrichs wrote:
| > To start with we'd basically like to replace the following
| > expressions for loading a Metacello
| > project:
| >
| >   Gofer new
| >     squeaksource: 'MetacelloRepositorty';
| >     package: 'ConfigurationOfSeaside30';
| >     load.
| >   ((Smalltalk at: #ConfigurationOfSeaside30) version: '3.0.6')
| >   load: #('Base').
| >
| > with something like the following:
| >
| >   Metacello new
| >     project: 'Seaside30';
| >     squeaksource: 'MetacelloRepository';
| >     version: '3.0.6;
| >     load: #('Base').
| >  
| Just for ascetics, can we lose the #new.  Since #project: is always
| required having it on the class side can just forward to the instance
| side.  I think the enforced convention of requiring 'project:' to
| always
| be the first message is reasonable. Maybe even...
| Metacello class >> new
|     ^ self confirm: 'Usage: Metacello project:'
|     "I had first thought to use 'self error: ' but the user really
| doesn't need to be presented with a prelude to a debugger."
| > If you're familiar with GoferProjectLoader, you'll see that I'm not
| > quite following their API, but
| > I have my reasons which should become apparent as I move forward.
| >
| > I think that the above Metacello-expression nicely replaces the
| > Gofer-expression, but by eliminating
| > Gofer from the equation we have lost the ability to simply load the
| > configuration package itself,
| > but that's easily addressed by adding a #get command:
| >
| >   Metacello new
| >     project: 'Seaside30';
| >     squeaksource: 'MetacelloRepository';
| >     get.
| >  
| Maybe make that #getConfiguration, since you are not downloading the
| whole project.  Once downloaded this might return the class
| ConfigurationOfXXX, so that #getConfiguration can be followed by
| #browse
| to invoke a standard tool to review it.
|
| Perhaps have #downloadComponents to download all individual component
| mcz files which can be browsed with standard Monticello tools.  That
| would require something like #listComponents so that the user would
| know
| which mcz files to look at.
|
| And/Or... It would be good to preview changes to the system.  I don't
| know how to do this currently.  Similar to how Monticello has the
| <Browse> and <Changes> buttons which provide  "Snapshot of
| Some.1.mcz"
| and "Changes from..."  Metacello might invoke the same Monticello
| dialogs but with a list of component mcz files rather than just one.
| Maybe...
|
| Metacello project: 'Seaside30'
|     previewChanges
|
| Metacello project: 'Seaside30'
|     browse
|
| > which just loads the ConfigurationOfSeaside30 package from the
| > 'http://www.squeaksource.com/MetacelloRepository'
| > repository.
| >
| > Before moving on I would like to mention that I can imagine a case
| > where the following expression
| > would be useful (no repository specification):
| >
| >   Metacello new
| >     project: 'Seaside30';
| >     get.
| >
| > I suggest that when the repository is not included then a
| > platform-specific search order be
| > used ... This would be one of the places where Pharo or Squeak
| > could introduce the notion of a set of
| > platform-approved repositories.
| >  
| Replace #squeaksource: with #repository:  (or #fromRepository: to be
| more DSL like).  It is better to be more generic than hardcoding a
| reference to one website/system.
|
| Do you mean to implement the platform specific search order like the
| 'Repositories' class variable in GoferProjectLoader?
|
| Do you also mean to implement the ManagedProjects class variable of
| GoferProjectLoader?
| I want to be able to do something like...
|    Metacello currentVersions
|    Metacello listAvailableUpgrades
|    Metacello versionOf:  "Answer current loaded version of project"
|
| Are these under consideration (just renamed from
| GoferProjectLoader)...
| Metacello search: "Looks for project aString scanning all
| repositories"
| Metacello repositories list   - but I don't know where the output
| should
| go to - Transcript, a new dialog or gui popup.
| Metacello repositories add:
| Metacello repositories listProjects.
| Metacello list "Lists all available projects, scanning all
| repositories"
|
| & GoferProject load "Reloads current version"
| > In a similar vein, I also would like to include the following:
| >
| >   Metacello new
| >     project: 'Seaside30';
| >     signature: 'dkh.375';
| >     get.
| >  
| I like the signature option.
| > Which would load an explicit version
| > 'ConfigurationOfSeaside30-dkh.375' of the configuration package
| > ... This would allow one to write something like the following:
| >
| >   (Metacello new
| >     project: 'Seaside30';
| >     signature: 'dkh.375';
| >     version: '3.0.6';
| >     get)
| >       compare:
| >         (Metacello new
| >           project: 'Seaside30';
| >           signature: 'dkh.380';
| >           version: '3.0.6';
| >           get).
| >
| >  
| Providing a comparison of configurations is a useful user function.
| Where does the output go?
| > But I'm getting a bit ahead of myself... Getting back to the load
| > operation:
| >
| >   Metacello new
| >     project: 'Seaside30';
| >     squeaksource: 'MetacelloRepository';
| >     version: '3.0.6;
| >     load: #('Base').
| >
| > I think that the #fetch and #record variants need to be included,
| > so we should support the following:
| >
| >   Metacello new
| >     project: 'Seaside30';
| >     squeaksource: 'MetacelloRepository';
| >     version: '3.0.6;
| >     fetch: #('Base').
| >
| >   Metacello new
| >     project: 'Seaside30';
| >     squeaksource: 'MetacelloRepository';
| >     version: '3.0.6;
| >     record: #('Base').
| >
| >  
| I am not clear on the function of #fetch and #record
| > So the API has STATE messages and ACTION messages. The STATE
| > messages (project:, version:, squeaksource:, signature:, branch:,
| > etc.) won't have interesting return values. You have to use one of
| > the ACTION messages (get, load, load:, fetch, fetch:, record,
| > record:, compare:, etc.) to have an interesting return value.
| >
| > Since we're building a scripting API, it might be convenient to
| > create a script that doesn't involve a ConfigurationOfXXX class
| > being created. This API would be used for projects that involve
| > one or two packages and maybe a project or two where the simplest
| > script would be something like the following:
| >  
| It seems you are quite keen on this as it was the majority of the
| post,
| but I would avoid this for now.   Don't try to solve the world all at
| once.   My aim was to make the simple case simpler - and address the
| "marketing" of Metacello not having a visible front-end in the image.
|
| Your short example provided below looks too complicated for casual
| use
| and intimidating for newbies.  To me it looks like "developer" stuff
| that I haven't had to deal with yet - ignoring the fact that I'll
| need
| to learn this sometime.   For now, raise the comfort level of the
| Metacello "users" by keeping this class focussed as a "user" tool and
| in
| particular new users.   Separate the "user" and "developer" concerns
| and
| do this one thing well.  The smaller concept and codebase will be
| easier
| for others to swallow.
|
| I wonder also if avoiding the creation of ConfigurationOfXXX may
| dilute
| the consistency of the Metacello concept - but I'm not in a position
| to
| judge that.  Perhaps consider this later and perhaps as a separate
| tool.
| >   Metacello new
| >     project: 'MyProject';
| >     for: #common
| >       do: [:spec |
| >         spec
| >           repository: 'http://www.squeaksource.com/MyProject';
| >           package: 'MyProject'. ];
| >     load.
| >
| > So yes, this script boils down to a simple Gofer script that looks
| > like the following:
| >
| >   Gofer new
| >     url: 'http://www.squeaksource.com/MyProject';
| >     package: 'MyProject';
| >     load.
| >
| > But you can't easily expand a Gofer script to make 'MyProject'
| > dependent upon 'Seaside30':
| >
| >   Metacello new
| >     project: 'MyProject';
| >     url: 'http://www.squeaksource.com/MyProject';
| >     for: #common
| >       do: [:spec |
| >         spec
| >           project: 'Seaside30' with: [
| >             spec
| >               version: '3.0.6';
| >               repository:
| >               'http://www.squeaksource.com/MetacelloRepository'.
| >               ];
| >           package: 'MyProject' with: [ spec requires: 'Seaside30'].
| >           ];
| >     load.
| >
| > and if you don't like the #for:do: style then perhaps something
| > like the following from the MetacelloToolBox API:
| >
| >   Metacello new
| >     project: 'MyProject';
| >     url: 'http://www.squeaksource.com/MyProject';
| >     for: #common;
| >     projects: {
| >           Metacecello new
| >             project: 'Seaside30';
| >             version:'3.0.6';
| >             url: 'http://www.squeaksource.com/MetacelloRepository'.
| >             };
| >     packages: #('MyProject');
| >     dependencies: {'MyProject' -> #('Seaside30')};
| >     load.
| >
| > We can work through the details of the API later, the important
| > point is that one can write a load script that includes package
| > and project dependencies without ever having to create and save a
| > ConfigurationOfMyProject class/package. Naturally, it is only a
| > couple more steps to being able to create (create command creates
| > the ConfigurationOf class) and save (commit: the
| > ConfiguarionOfMyProject package to the MyProject repository) the
| > configuration when the time is right:
| >
| >   Metacello new
| >     project: 'MyProject';
| >     url: 'http://www.squeaksource.com/MyProject';
| >     version: '1.0';
| >     for: #common
| >       do: [:spec |
| >         spec
| >           project: 'Seaside30' with: [
| >             spec
| >               version: '3.0.6';
| >               repository:
| >               'http://www.squeaksource.com/MetacelloRepository'.
| >               ];
| >           package: 'MyProject' with: [ spec requires: 'Seaside30'].
| >           ];
| >     create;
| >     save: 'Monticello commit comment'.
| >
| > A similar style can be used to edit existing configurations
| > programmatically as well...
| >
| > Well I think that by now you get the basic idea ... upgrade,
| > compare, list upgradable projects, etc. are some of the commands
| > that would need to be added, but for those guys it is a matter of
| > just adding/implementing the necessary commands ...
| >
| > Oh, I almost forgot, but the basic mechanisms for doing all of the
| > above already exist in Metacello. Between the MetacelloToolBox API
| > and the version constructors all of these commands will be
| > straightforward to implement, so I think that it will come down
| > down to:
| >
| >   a) deciding where the cutpoint for the API should be (i.e., just
| >   stick to loading)
| >  
| Just stick to "user" operations - listing/loading/comparison.  No
| project creation stuff.
| >   b) deciding between for:do: and MetacelloToolBox API ...
| >  
| Following my opinion on a), this is not applicable.
| > I'm somewhat partial to the for:do: style since it is consistent
| > with the existing specification api for configurations, however,
| > the MetacelloToolBox API style may easier for newcomers to grasp
| > and may provide a bridge for newcomers that introduces folks to
| > the for:do: style.
| >
| > Anyway, I'm interested in hearing feedback ...
| >
| > Dale
| >  
|
|
Reply | Threaded
Open this post in threaded view
|

Re: Metacello Scripting API (strawman)

otto
Wow, Dale, what a lot to chew on. I didn't follow the thread, but
since your prompting I'm trying to catch up.

>  Metacello new
>    project: 'MyProject';
>    version: '3.0.6';
>    fetch.
>
>  (Metacello project: 'MyProject')
>    version: '3.0.6';
>    record.

Yes, makes sense. These tools would be useful when upgrading to newer versions.

> I tend to feel that there should be a bit of compatibility between Gofer and Metacello (using `new` in scripts, supporting `squeaksource:`, `gemsource:`, `blueplane:`,etc.). Where common concepts are used there should be a common way of expressing them ...

What about MetaGofer? haha. Well, why not merge? In a sense, Metacello
is a Gofer for projects.

> I think that there is value in the GoferProjectLoader features that manage a set of personal repositories and projects. The features that you mention do fall into the category of tools (for the most part) and I want to draw a line between support for tools and maintaining tools.

>  - commit dirty mcz files, update configuration, commit configuration
>  - create new version or baseline

yes! we did something like this in our dev image, essentially just
using metacello to list the relevant packages and and then we commit
them all in one shot.

> | >   Metacello new
> | >     project: 'Seaside30';
> | >     squeaksource: 'MetacelloRepository';
> | >     version: '3.0.6;
> | >     load: #('Base').

Yes, nice. Or perhaps if you have a configuration base class, it could
live there?

> | >       compare:

good idea, useful for upgrading.

> | Just stick to "user" operations - listing/loading/comparison.  No
> | project creation stuff.
> | >   b) deciding between for:do: and MetacelloToolBox API ...

Feels as if there are too many ways then; perhaps just say that if you
want a project with dependencies, create a configuration. That's how.
And then create a superclass with convenience methods to make it
easier to create a really simple project.