Skip to content

Conversation

@RJCD-Diamond
Copy link
Contributor

@RJCD-Diamond RJCD-Diamond commented Nov 28, 2025

The client that exists in blueapi is functional. This class extends the ability of the client, abstracts a lot of the logic and allows beamline staff or users to start building scripts used for an experiment.

@RJCD-Diamond RJCD-Diamond requested a review from a team as a code owner November 28, 2025 14:38
@RJCD-Diamond
Copy link
Contributor Author

@EmsArnold

@RJCD-Diamond RJCD-Diamond changed the title Add a UserClient that can be used a scripting interface for blueapi feat: Add a UserClient that can be used a scripting interface for blueapi Nov 28, 2025
@codecov
Copy link

codecov bot commented Nov 28, 2025

Codecov Report

❌ Patch coverage is 89.56522% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.69%. Comparing base (d8a989c) to head (266aaa0).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/blueapi/client/user_client.py 88.78% 12 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1284      +/-   ##
==========================================
- Coverage   94.92%   94.69%   -0.23%     
==========================================
  Files          42       43       +1     
  Lines        2717     2828     +111     
==========================================
+ Hits         2579     2678      +99     
- Misses        138      150      +12     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@RJCD-Diamond
Copy link
Contributor Author

RJCD-Diamond commented Nov 28, 2025

@abbiemery @DominicOram @EmsArnold @olliesilvester @Relm-Arrowny @oliwenmandiamond @noemifrisina

I have a feeling this may be controversial, so I would like opinions on this. This has been extremely useful for saxs-bluesky and IMO it means we have something closer to a minimum viable Domain-Specific Language (DSL)

@olliesilvester
Copy link
Contributor

olliesilvester commented Dec 1, 2025

There's definitely a need for this sort of thing. How have scientists/users been using this so far, and is there feedback?

I've experimented with similar things using ipython and jupyter notebooks, but it's hard to make it not clunky

@RJCD-Diamond
Copy link
Contributor Author

Scientists have been experimenting with this on i22 and @EmsArnold has used this. I'd say feedback has been broadly positive. The only complaint i've had is the clunkiness of having to put client.run() to execute a plan via blueapi.

@olliesilvester
Copy link
Contributor

Good to know, I'm a fan of this. I wonder if users would prefer to do this sort of thing in jupyter notebooks or just in a basic terminal. I guess it works fine for both anyway.

Maybe this can be a topic for the next athena drop-in, we can work out the best API + features for this

@Relm-Arrowny
Copy link
Contributor

Relm-Arrowny commented Dec 2, 2025

Not sure this is controversial, blueapi as it is, is very hard to use to run any experiment and this make it much easier.

Kind of related, we run a jupiter server on p99-k8s with an "option" of using the nexus writer for scientist to play with, it may be of interest. This is the startup I gave scientist https://github.com/DiamondLightSource/sm-bluesky/blob/main/demo/p99/stomp_setup.ipynb. You can play with it here: http://172.23.177.194:8888/lab/tree/work it is password protected, I can dm you the password if needed.

We all trying to found ways to make it easier.... may be it is time we try to come up with something we all use?

@RJCD-Diamond
Copy link
Contributor Author

Good to know, I'm a fan of this. I wonder if users would prefer to do this sort of thing in jupyter notebooks or just in a basic terminal. I guess it works fine for both anyway.

Maybe this can be a topic for the next athena drop-in, we can work out the best API + features for this

Sounds good!

@RJCD-Diamond RJCD-Diamond changed the title feat: Add a UserClient that can be used a scripting interface for blueapi feat: Add a UserClient that can be used as a scripting interface for blueapi Dec 3, 2025
@iain-hall
Copy link

I would find this useful as well. At some point I came up with some functions to wrap Blueapi calls to do something very similar, so having a common standard solution to this problem wouild be good. My current method for testing Blueapi with real hardware on a beamline is fire up GDA and use the Jython console!

@DominicOram
Copy link
Contributor

I'm not per-say against this if people find it useful but I would say if you take a step back and look at the whole system it kind of feels a bit odd. My understanding was that some of the arguments for using Bluesky in the first place were:

  • It's python, meaning that scientists can easily modify what plans are doing
  • It's used across facilities, meaning we can hopefully leverage shared plans, docs and features that it has out of the box

My concern with this change is that now we will have an explosion of "plans" that are:

def my_plan():
    client.run("a")
    client.run("b")

and I worry that:

  1. Scientists have no way of controlling what "a" and "b" do.
  2. They have no way of doing some of the more useful things that Bluesky offers out of the box like running "a" and "b" in parallel
  3. Converting my_plan into something that's generically useful, server-side and maintained by the DAQ team is not trivial
  4. There is no autocomplete or potential for IDE highlighting on the args for what you're running through the client
  5. You're lost all the simulation ability of the RE, I can no longer do list(my_plan) to give me what the plan is actually doing
  6. You don't have the ability to actually read the hardware. I can't do something like running "a" until the temperature reaches a certain point then run "b"

To allow scientists to be able to do any of these things you then have the option of:

  1. Add more complexity to the UserClient and BlueAPI
  2. Teach scientists how to actually write plans and get them to add them to the server

My preference is to go down the second path as I think 1) will just lead to even more DLS custom code we will have to maintain and pull us further from the collaboration. Which means I think as part of this I would like us to decide roughly what the line is of what this DSL will and won't support and when we will start teaching scientists to use Bluesky as intended. I would also like us to think about how we can make the transition from a scientists writing things using the DSL to writing plans as easy as possible even small stuff like still using mv rather than move would help. Again, needs documenting.

For this specific implementation I have some comments:

  • I think we should be able to install just the blueapi client and not the whole server to avoid bloat e.g. pip install blueapi[client]
  • We're trying to move away from blueapi depending on dodal. I'm not actually sure whether you need the inject in here
  • This needs quite a bit of user facing docs
  • If we dislike client.run we can make it shorter, e.g. override __call__ like the RE does and just do client("count", ...)
  • I'm not sure how this is going to work with auth?

P.S. I'm not arguing btw that Bluesky is easy to teach. I think in particular the use of generators is really unfriendly to novices and not worth the benefit you get from it. However, the decision has been made and if all of our backend logic is going to be Bluesky at some point we will have to start teaching more advance users how to use it properly

@RJCD-Diamond
Copy link
Contributor Author

RJCD-Diamond commented Dec 5, 2025

There's a lot to unpack here, so I will try but this is probably discussed in person.

I'm not per-say against this if people find it useful but I would say if you take a step back and look at the whole system...

That's a whole conversation in itself, which I will leave to those that work in DAQ full time

My understanding was that some of the arguments for using Bluesky in the first place were:
It's python, meaning that scientists can easily modify what plans are doing
It's used across facilities, meaning we can hopefully leverage shared plans, docs and features that it has out of the box

We lost these when we put bluesky behind an API, and then poked it with a request. This class attempts to put it back in python world, and return some of the python-y aspects, whilst also having all the advantages of blueapi.

Teach scientists how to actually write plans and get them to add them to the server

This is the plan, but once they have written their plan - how do they execute it? We're trying to replace gda, and if they don't have a nice method to execute it, we'll be stuck in gda world (see Iain's comment). This provides a link between the user and blueapi without going through jython.

  1. Scientists have no way of controlling what "a" and "b" do.
  2. They have no way of doing some of the more useful things that Bluesky offers out of the box like running "a" and "b" in parallel
  3. Converting my_plan into something that's generically useful, server-side and maintained by the DAQ team is not trivial
  4. There is no autocomplete or potential for IDE highlighting on the args for what you're running through the client
  5. You're lost all the simulation ability of the RE, I can no longer do list(my_plan) to give me what the plan is actually doing
    6.. You don't have the ability to actually read the hardware. I can't do something like running "a" until the temperature reaches a certain point then run "b"
  1. True, but again this is the limits from within which we are working. If they want that control they will need to write bluesky plans.
  2. BlueAPI doesn't have this ability, and that is beyond the scope of this PR. This could be solved with run(parallel=True) or something when that feature is available.
  3. This is basically the reason why we have gda user_scripts that aren't maintained
  4. There is, sorta and could be improved. This is why you can pass a callable of the plan, that way it can at least let you pass args. I will improve this so if you pass kwargs that aren't in the plan it will complain. Maybe I should just remove the ability to pass a plan_name as a str at all.
  5. Again this happened when we put it behind an API. This PR won't address this, and just attempts to make it easier to use blueapi, if you want to use blueapi - which I think we should as much as possible. I think it's crazy to tell beamline scientist to use a bluesky run engine on their local machine in juypter notebooks when they're doing commissioning/developing. They should be commissioning/developing within the environment we support. This can be used in a notebook.
  6. Again this happened when we put bluesky behind an API. However, this PR does somewhat address this. The callback stores that info in the docs, which can be accessed. The livetable is printed correctly. And if you use a matploliblib WebAGG backend you also get LivePlotting. (Only works on WebAgg because most plotting frontends demand that it is run in the main thread, which the client doesn't do) However - tiled should address this, so I'm told.

def my_plan():
client.run("a")
client.run("b")

Is that any different from having (in gda):

def my_plan():
    run_plan("a")
    run_plan("b")

I don't know how to resolve this if scientists need to write custom scripts. The only way we can prevent this is by not letting anyone modify/write scripts and stick it all behind a GUI, which we cannot do. Or insist we have everyone submit everything and it goes through code review. Which is impracticable. We should be following the ALARP principle (as low as reasonable achievable) ie keep the crappines of the code as low as reasonably achievable, without hindering the science.

We're trying to move away from blueapi depending on dodal.

This does not depend on dodal, only for the pytest. This can be removed.

If we dislike client.run we can make it shorter, e.g. override call like the RE does and just do client("count", ...)

I like this

I'm not sure how this is going to work with auth?

This works with auth. i22/b21 currently have the latest version of blueapi and user numtracker etc. The user must first login. BlueAPI does this via blueapi -c /path/to/ixx_config.yaml login This could be wrapped so it's nicer too.

@olliesilvester
Copy link
Contributor

I agree with a lot of Dom's concerns. For me though, I am now aware of at least 4 different implementations where someone in DAQ has written some sort of BlueAPI wrapper purely for the purpose of allowing scientists to easily run bluesky plans through a terminal.

Given that loads of us are trying to do the same thing ATM, it would be good to have a simple but stable solution we can all use asap

@Relm-Arrowny
Copy link
Contributor

Relm-Arrowny commented Dec 5, 2025

To allow scientists to be able to do any of these things you then have the option of:

  1. Add more complexity to the UserClient and BlueAPI
  2. Teach scientists how to actually write plans and get them to add them to the server

I don't believe Option 2 is the core issue. Instead, I personallty think BlueAPI does not deliver the same User Experience as GDA. While scientists writing and submitting plans to the server is fine, we need an experience that closer to our current user expectation.
I feel we are not adequately accounting for our current user expectations. Many users require a scripting-like experience, they running experiments interactively at the terminal, executing custom scripts for simple scan/movement stacking or complex operations (like bespoke controls loop, custom UBMatrix or on the spot analysis to guide the next steps). The current BlueAPI is so restrictive that it will likely be a source of friction for these users.

@abbiemery
Copy link
Contributor

A scripting interface for blueapi is something the core team have visibility on, and are looking to prioritise in the new year. So thank you for curating your experiences and opinions here. I will be at the athena drop in session next week to discuss this with you all :)

@RJCD-Diamond
Copy link
Contributor Author

RJCD-Diamond commented Dec 5, 2025

After Dom's long comment, and my equally long response we spoke about this IRL.

The summary from that conversation:

  • There is a need for this
  • If we do this, it is probably advisable to have the usage of this be as close how the native run engine works. Do not pass strings, pass plans/devices imports from dodal/village-bluesky. Such that write actual bluesky plans isn't much of a steep learning curve
  • Not having a scripting interface is only possible if everything is a UI for everything which is probably unachievable
  • We might want a way to serialise and send bluesky plans via the client so that the beamline scientists can write custom one off plans on the client side and not have to commit/reload.
  • Beamline scientists are developers and we want them to write bluesky plans. Therefore make the barrier for entry of writing bluesky very low.
  • If this, or something similar, is used we should mirror what ISIS do. Have cron-like jobs to do daily commits of staff scripts
  • In order to prevent complex logic being developed on the client side instead of the bluesky side, we might want automations that flag complex logic and encourage the staff to write bluesky plans.

@DominicOram did I forget anything? I think I probably did

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants