WEBVTT

00:00.000 --> 00:06.400
Thanks, everyone.

00:06.400 --> 00:09.520
So yeah, like Seth said, I've been working on KeyCAD for a long time.

00:09.520 --> 00:14.720
If you're new to the world of open hardware and haven't heard of KeyCAD yet, welcome.

00:14.720 --> 00:19.040
It's a CAD tool, mostly for designing electronics for printed circuit board design, but

00:19.040 --> 00:21.400
also has a few other applications.

00:21.400 --> 00:25.880
So I'm going to be talking about one of the new features, which is coming in KeyCAD 9.

00:25.880 --> 00:29.920
If you want to hear about the other 500 features, stick around for Wayne's talk a little

00:29.920 --> 00:33.600
later, and KeyCAD 9 will be out shortly.

00:33.600 --> 00:37.600
It was going to be out the end of this week, but it's going to be next week because

00:37.600 --> 00:41.320
fuzz them and things stick around.

00:41.320 --> 00:46.880
So to talk about what I did here, I have to start by talking about why I did it.

00:46.880 --> 00:51.920
If you're familiar with KeyCAD, you probably know that it already has a plug-in system.

00:51.920 --> 00:56.440
KeyCAD has had the ability to add Python plug-ins for quite a long time, and if you're

00:56.480 --> 01:01.120
really into KeyCAD, maybe you've even tried to write some of your own plug-ins.

01:01.120 --> 01:06.000
So why did I make an API if we already have an API?

01:06.000 --> 01:11.720
So the current Python plug-in system is mostly around a tool called Swig, which is a

01:11.720 --> 01:16.840
clever tool that can analyze mostly C++ code, and now they also support C.

01:16.840 --> 01:21.400
And it automatically generates wrappers in a variety of different languages, and allows

01:21.400 --> 01:26.640
you to, for example, call C++ functions directly from Python.

01:26.640 --> 01:33.480
So in the case of KeyCAD, a subset of our C++ application is wrapped using Swig into a Python

01:33.480 --> 01:40.200
module, and plug-ins can then just import that Python module and call into KeyCAD code.

01:40.200 --> 01:41.120
So this is pretty cool.

01:41.120 --> 01:43.800
We don't have to do that much work.

01:43.800 --> 01:46.040
Code is mostly generated for us.

01:46.040 --> 01:49.760
We have some extra code that we had to write, but not that much.

01:49.760 --> 01:54.600
And now Python-based tools can do a lot of different things with KeyCAD, which has been

01:54.600 --> 02:00.400
really great for the ecosystem, because there is now a whole range of tooling that adds

02:00.400 --> 02:07.200
on to KeyCAD does specific things or things that we hadn't yet supported in the main C++

02:07.200 --> 02:10.680
code base, which is pretty good, right?

02:10.680 --> 02:16.600
Well, maybe this is a bit obvious in hindsight, but this really wasn't the best choice

02:16.600 --> 02:22.840
to deliver an API that works the way that people expect when they hear the phrase API,

02:22.840 --> 02:28.880
like not having the functions you call change every version, or not being able to crash

02:28.880 --> 02:32.680
KeyCAD, if you call functions in the wrong order.

02:32.680 --> 02:38.920
So the main challenge is with Swig, our cover, like a couple of different places.

02:38.920 --> 02:44.800
So first of all, from the point of view of us, the KeyCAD development team, like I said,

02:44.800 --> 02:46.720
the interface is really fragile.

02:46.720 --> 02:50.520
There's no API layer within the KeyCAD code base.

02:50.520 --> 02:55.280
It was just directly, let's take the existing things that KeyCAD is doing, let's make it

02:55.280 --> 02:57.680
so that you can call them from Python.

02:57.680 --> 03:02.040
And this means that we are constantly dealing with challenges when we want to refactor

03:02.040 --> 03:08.000
that code, when we want to deprecate something, or add a new way of doing things, or just

03:08.000 --> 03:12.080
change how we do things internally in order to improve KeyCAD itself.

03:12.080 --> 03:16.840
We have to decide, are we going to just break these plugins that are expecting this

03:16.840 --> 03:22.560
old interface, which we sometimes have to do, unfortunately, or are we going to add some

03:22.560 --> 03:27.120
way of preserving backwards compatibility, which sometimes is pretty easy and sometimes

03:27.120 --> 03:33.280
is impossible and often is forgotten about until later, which is annoying for all of the

03:33.280 --> 03:35.200
Python developers.

03:35.200 --> 03:40.360
In addition to that, which is a big pain for a lot of people, Swig is also a little bit

03:40.360 --> 03:44.720
annoying for us on the development team, because we've been moving to use more and more

03:44.720 --> 03:52.040
modern C++ APIs and types, and Swig is slowly getting better at this, but it's still

03:52.040 --> 03:57.120
not, you know, it's not keeping pace with how we adopt C++ features.

03:57.120 --> 04:00.600
And it also slows down the build process for us, which limits how fast we can iterate

04:00.600 --> 04:02.600
on things.

04:02.600 --> 04:07.640
And like I said, Python plugins are directly reaching into KeyCAD as it is running the

04:07.880 --> 04:11.880
same process, they have access to all that memory.

04:11.880 --> 04:16.480
If they do things that don't match the expected contract, that we were thinking about when

04:16.480 --> 04:21.680
we wrote the code, they can just completely break things in very weird ways and cause

04:21.680 --> 04:25.000
an interesting bug reports.

04:25.000 --> 04:27.080
But it doesn't stop there.

04:27.080 --> 04:31.640
The current Python plugin system basically lets plugins assume that they Python bindings

04:31.640 --> 04:36.120
to our core framework library, WSWGets, are available.

04:36.120 --> 04:42.360
And sometimes this has been interesting for packaging, because that binding WX Python

04:42.360 --> 04:48.040
is sometimes out of sync with WX widgets in different platforms, and we've had to patch

04:48.040 --> 04:53.440
around that, and basically spend a bunch of energy maintaining things on the windows and

04:53.440 --> 04:55.840
macOS side, especially.

04:55.840 --> 05:01.360
We also have to bundle our own Python interpreter on those platforms, because we need to ensure

05:01.360 --> 05:06.440
for these plugins that they have, all of these Python modules available with appropriate

05:06.440 --> 05:11.840
versions, and we can't rely on that being installable externally.

05:11.840 --> 05:17.480
So we have to now ship a Python environment, and plugins have to use that environment,

05:17.480 --> 05:23.520
which is challenging for them if they want to then add external Python dependencies, and

05:23.520 --> 05:27.760
sometimes it's just not possible for them to use certain Python dependencies.

05:27.760 --> 05:32.000
There's one Python environment shared by everything, which if you're a Python developer,

05:32.000 --> 05:36.160
you know, is just not a great idea.

05:36.160 --> 05:42.200
If that wasn't enough, it's also not great as a developer if you're trying to build plugins,

05:42.200 --> 05:50.080
because using keycads to run your Python code, the way that it runs is a little bit different

05:50.080 --> 05:55.320
than the way that you would typically run a Python program, and so if you're trying to test

05:55.360 --> 06:00.560
your code, if you're trying to debug in an IDE or anything like that, it's sometimes

06:00.560 --> 06:05.240
possible, but it's very hard to get exactly the same environment and run it in exactly

06:05.240 --> 06:06.440
the same way.

06:06.440 --> 06:10.400
So sometimes you just have to test things the brute force way.

06:10.400 --> 06:15.120
We have a built-in Python console that lets you have a Python repel and just test things

06:15.120 --> 06:19.800
out, but if you're used to developing Python, maybe you're used to a little bit nicer

06:19.800 --> 06:26.240
tooling, and this built-in console is something that the keycad team now has to maintain,

06:26.240 --> 06:32.200
and it's another challenge and another thing that makes developing for keycad a little

06:32.200 --> 06:37.560
bit bespoke compared to other kinds of Python development.

06:37.560 --> 06:42.200
So that's where we are, and it's taken a long time to develop something better along the

06:42.200 --> 06:46.800
way we considered a few options that we then didn't do, which I think are an interesting

06:46.800 --> 06:48.200
dimension.

06:48.200 --> 06:52.240
So first of all, we could have just made a real API layer in C++, and then pointed

06:52.240 --> 06:55.040
to Swiget that instead of at the internals.

06:55.040 --> 06:58.720
This would have been relatively straightforward, and it would have probably totally solved

06:58.720 --> 07:03.480
those fragility problems, where you know, function names are changing every keycad version.

07:03.480 --> 07:07.000
The issue is that most of those other problems would have remained.

07:07.000 --> 07:12.240
So we have known for a while that we wanted to move away from Swig, and we also spend a little

07:12.240 --> 07:17.760
while looking at a library called Pi by 11, which is kind of serving the same kind of function

07:17.760 --> 07:23.480
as Swig, but in a more manual way where you have more control over how it works.

07:23.480 --> 07:28.480
And this might have solved a few more of the problems, but definitely not all of them.

07:28.480 --> 07:33.760
So about two years ago, I wrote an RFC for the team that basically said, what if we went

07:33.760 --> 07:35.200
in a different direction here?

07:35.200 --> 07:39.360
What if we could completely remove Python from the core of keycad and build a different

07:39.360 --> 07:41.000
kind of API?

07:41.000 --> 07:45.520
So over that window, I built a proof of concept, and it seemed to be working pretty well,

07:45.520 --> 07:50.160
some time passed, and here we are now about to ship the real version of this with keycad

07:50.160 --> 07:51.160
9.

07:51.160 --> 07:54.240
So let's talk about the IPC API.

07:54.240 --> 07:57.400
What I wanted in this API can basically be summed up like this.

07:57.400 --> 08:02.200
First of all, we wanted to be able to change any internals in keycad and hide that change

08:02.200 --> 08:04.000
from all the API users.

08:04.000 --> 08:08.560
We should be able to do normal things that people expect, like have a sane deprecation

08:08.560 --> 08:13.360
policy, and have forwards and backwards compatibility wherever possible.

08:13.360 --> 08:18.640
Second of all, API users should no longer have direct access to keycad internal state.

08:18.640 --> 08:23.880
We want to run them in external processes and keep them from doing, let's say, accidental

08:23.880 --> 08:25.480
evil.

08:25.480 --> 08:29.920
And third, the developer experience is important, both for us the keycad team and for all

08:29.920 --> 08:34.960
of the API users, if we want this thing to be adopted and useful, it has to be better

08:34.960 --> 08:39.720
than what exists out there right now, not just different.

08:39.720 --> 08:41.520
So here's how it works at a high level.

08:41.520 --> 08:46.480
The API is using protocol buffers to define messages, messages that are passed back and

08:46.480 --> 08:52.160
forth between keycad and an external application over unic sockets or Windows name pipes.

08:52.160 --> 08:56.120
And we use a library called nanomessage next generation, which I'll just call NNG from

08:56.120 --> 09:02.920
now on because it's shorter as an abstraction layer over those sockets and pipes.

09:02.920 --> 09:04.120
So let's start at the bottom.

09:04.120 --> 09:05.120
Why NNG?

09:05.120 --> 09:06.720
It's a question I get sometimes.

09:06.720 --> 09:10.600
I looked at a number of different options that could solve the problem I had where I want

09:10.600 --> 09:15.680
to send bytes back and forth between keycad and other things on the same machine.

09:15.680 --> 09:20.840
And basically, NNG came out on top because it's pretty simple to use and very few lines

09:20.840 --> 09:21.840
of code.

09:21.840 --> 09:27.200
And those very few lines of code are using the native platform IPC mechanisms.

09:27.200 --> 09:31.520
The same code does the right thing on Windows or on non-Windows and you don't have to

09:31.520 --> 09:34.640
care that much about the differences there.

09:34.640 --> 09:39.840
And it has all the availability we needed it to be in terms of what platforms it supported

09:39.840 --> 09:42.360
and what languages it supported.

09:42.360 --> 09:45.320
And basically, I didn't find a good reason not to use it.

09:45.320 --> 09:49.640
And I also looked at a lot of other options so you can see some of them down here.

09:49.640 --> 09:55.400
And all of these other options came out as either more complicated or they had some drawback

09:55.400 --> 10:00.800
or in some way they were trying to solve a different set of problems than my problems.

10:00.800 --> 10:07.880
So I think there are great solutions for different problems but they weren't the one for me.

10:07.880 --> 10:10.640
So then one layer up why a protobuff.

10:10.640 --> 10:15.520
So if you're not familiar with protobuff, basically is a project from Google where you define

10:15.520 --> 10:21.840
messages using a domain-specific language and then use a tool that compiles that DSL into

10:21.840 --> 10:27.400
various different wrappers essentially and a bunch of different target languages that

10:27.400 --> 10:29.280
implement those messages.

10:29.280 --> 10:35.720
And we use this because we can then define most of the keycad API in terms of those DSL messages

10:35.720 --> 10:38.760
which are pretty easy to parse but look at some in a bit.

10:38.760 --> 10:43.880
And it means it's really easy to keep ccad synced up with the third party language bindings.

10:43.880 --> 10:49.400
So protobuff is not perfect and in fact it has some downsides that are important to be aware

10:49.400 --> 10:52.200
of if you want to use it for your project.

10:52.200 --> 10:56.880
But ultimately I did look at a number of alternatives to protobuff and they either didn't

10:56.880 --> 11:02.160
have all the features we need or they weren't nearly as popular and I decided after

11:02.160 --> 11:07.600
looking at what was available and all of the resources I could find people posting about

11:07.600 --> 11:11.320
challenges they had had and how they had overcome those challenges.

11:11.320 --> 11:16.360
I wanted to go with the thing that was the most widely used because I could see how these

11:16.360 --> 11:20.640
people were doing similar things and how they had solved these problems and some of the alternatives

11:20.640 --> 11:21.640
I looked at.

11:21.640 --> 11:25.320
There just wasn't that much information about people solving similar problems and I think

11:25.320 --> 11:28.040
that kind of thing is important.

11:28.040 --> 11:31.480
So here's some example protobuff messages from the keycad API.

11:31.480 --> 11:36.720
You can think of them kind of like structures if you know a language like cc++.

11:36.720 --> 11:42.520
You can see some of these have primitive types like these in 64s and then a lot of them

11:42.520 --> 11:47.160
are composed out of other messages internally.

11:47.160 --> 11:53.720
So here's an example of a command that an API client might want to send to get the bounding

11:53.720 --> 11:56.280
box or extends from a text object.

11:56.280 --> 12:01.200
So we're going to have this certain other message that specifies what the text is and we're

12:01.200 --> 12:05.920
going to get back that box too we just saw with the bounding box.

12:05.920 --> 12:09.600
So to actually send and receive these messages we have these what are called envelope

12:09.600 --> 12:15.640
messages that have a request and response inside as an any type which is a protobuff feature

12:15.640 --> 12:20.640
that basically lets you do runtime type introspection so that we can dynamically dispatch

12:20.640 --> 12:24.880
a handler depending on what kind of message we receive coming in.

12:24.880 --> 12:30.320
Protobuff defines a binary format that these messages get serialized into and that serialized

12:30.320 --> 12:33.560
format is what we send back and forth over the wire.

12:33.560 --> 12:39.360
And one note is that protobuff can also be serialized as text that is basically JSON.

12:39.360 --> 12:43.280
So we have a debugging feature where you can actually dump every message going back and

12:43.280 --> 12:48.000
forth to a text log and see what's going on which is really handy.

12:48.000 --> 12:52.040
So we have these messages how do we actually hook them up to keycad?

12:52.040 --> 12:56.000
At a super high level keycad is an event driven application one of our other devs e-in

12:56.000 --> 12:59.640
who's up there did a deep dive into this on our developer meetup on Friday and you

12:59.640 --> 13:03.880
can watch that on our YouTube channel if you want the full details but at a really high

13:03.880 --> 13:08.240
level events are coming in from various sources maybe from an input device maybe from

13:08.240 --> 13:13.240
the operating system and they get routed to various event handlers by it's spasher.

13:13.240 --> 13:18.120
This is all happening in a single thread so all these handlers are designed to be non-blocking

13:18.120 --> 13:22.320
and sometimes they have their own internal event loops and all of this is going on with

13:22.320 --> 13:27.480
various core routine magic that lets us have somewhat sane code but I'm going to skip

13:27.480 --> 13:29.320
over that today.

13:29.320 --> 13:34.480
So to hook into this I basically added a new type of event and this is called whenever

13:34.480 --> 13:38.720
any kind of API message comes in and that is routed to a new kind of handler which

13:38.720 --> 13:44.760
is handling the API messages and this handler is unpacking that envelope message and

13:44.760 --> 13:47.560
figuring out okay what should I do with this?

13:47.560 --> 13:53.240
It has its own that of handlers that are all supporting the actual API functions.

13:53.240 --> 13:58.400
Some of those functions might be able to return some calculation immediately some may be

13:58.400 --> 14:03.400
able to create their own other events and post those to the event loop that will then

14:03.400 --> 14:08.120
get handle that some later time so all of these have to be non-blocking essentially return

14:08.120 --> 14:13.280
to the client immediately so if you want to call an API command that is going to take

14:13.280 --> 14:18.720
some time to do you are just going to immediately get a reply that hey this command started

14:18.720 --> 14:22.600
and you're going to need to check back to see when it finished.

14:22.600 --> 14:26.200
Some of the details of this by the way can be kind of hidden from the actual users of

14:26.200 --> 14:31.640
the API through the client libraries to make it a little bit less complicated.

14:31.640 --> 14:35.960
And one other thing I should mention is that these API handlers are dynamically registered.

14:35.960 --> 14:41.080
So for example if you open a keypad project manager you might only have a few handlers

14:41.080 --> 14:45.560
but then when you open up the PCB editor it will register a PCB handler because now you

14:45.560 --> 14:50.200
can work with a board and now you can call get board and refill zones and things like that

14:50.200 --> 14:55.160
and if you close that PCB editor it will get de-registered and then if you say refill zones

14:55.160 --> 15:00.760
you would instead get back a message saying hey there's not a handler for that right now.

15:00.760 --> 15:05.000
So because of this design you know the API events are synchronous and are getting sequenced

15:05.000 --> 15:08.680
in with all of the user input so that's something you have to keep in mind as a plugin

15:08.680 --> 15:14.280
developer is that you're not kind of operating in parallel with the user but with the user.

15:14.280 --> 15:19.240
So you have to keep in mind how you want your plugin actions to get sequenced in

15:19.240 --> 15:24.760
as undue steps and sometimes the user will be doing something that we don't want to allow

15:24.760 --> 15:28.760
interruption like if you're in the middle of routing tracks we don't want your API plugin to be

15:28.760 --> 15:33.880
able to just delete the board. So sometimes the API will say hey I'm busy you need to try that again

15:33.880 --> 15:38.840
later. So that's an overview of how it's implemented but what about using it?

15:40.200 --> 15:45.160
Well we're releasing Python bindings for the API along with Kika 9 and you can actually install it right

15:45.160 --> 15:50.120
now if you have a nightly and want to try it out so it's there in the Python package index

15:50.120 --> 15:55.560
and that's the source code for it just make sure that you go into your Kika preferences and turn

15:55.560 --> 16:01.720
on the API because it's not on by default right now. So here's a simple example of creating a

16:01.720 --> 16:06.120
zone on whatever board is open we start by importing some things and then getting a handle to the

16:06.120 --> 16:11.960
open Kika instance and then the board and then we construct a zone object that has certain properties

16:11.960 --> 16:16.840
which is most of the code you see there and finally we put it on the board. By the way we could be

16:16.840 --> 16:23.000
developing this from any IDE or from a repel outside of Kika and it would work the same way as if it was

16:23.000 --> 16:27.960
running as a plugin from Kika so there's no longer any difference there you can use whatever kind of

16:27.960 --> 16:34.200
Python environment is most comfortable for you. One thing I want to point out is that these two lines

16:34.200 --> 16:40.360
are the only lines that are communicating with Kika using the API so the rest of it is building up

16:40.440 --> 16:44.920
objects in Python that are representing protobuff messages that will then be sent.

16:47.160 --> 16:52.440
You could also take away that a lot of steps to define an outline for a zone and this is true

16:52.440 --> 16:59.160
and I guess my point here is that even if we make the API really easy to use and Pythonic and all that

16:59.160 --> 17:05.080
good stuff you're still going to need to kind of understand Kika had some some places to understand

17:05.800 --> 17:10.360
the zone is complicated because it can actually have a arcs in its border and it can have internal

17:10.360 --> 17:16.440
cut out some things like this and so the API describes all of that so that just is on us to make

17:16.440 --> 17:20.360
sure that all of these things are documented well and have good examples for you to work from.

17:22.040 --> 17:25.960
One thing that I'm not going to have time for too much detail on is that there is a new

17:25.960 --> 17:31.320
Python plugin launching system coming with Kika at 9 which is using virtual environments per plugin

17:31.320 --> 17:38.200
and automatic dependency installation that mostly works and this you know I'm sure there's a few

17:38.200 --> 17:43.240
edge cases because that's Python where it doesn't work but for a few people who've been testing it

17:43.240 --> 17:47.640
it seems to work which is really awesome because now plugins can use whatever UI to locate they want

17:48.280 --> 17:54.520
and as a bonus it can launch any executable file so you don't necessarily need to use Python if you don't

17:54.520 --> 18:01.720
want to so Kika at 9 is coming from with the first public version of this API but I'm definitely

18:01.720 --> 18:05.240
not done there are a lot of features that are important to add that will be coming in future

18:05.240 --> 18:10.280
versions and probably some things I don't even know I should add so I'm definitely looking for

18:10.280 --> 18:15.400
feedback from early users of this you know up next I'm going to be working on integration with

18:15.400 --> 18:20.680
the footprint editor and replacing the footprint wizard systems so that we can have shared code

18:20.680 --> 18:27.240
base between our library team and Kika itself you know called back to the CAD query talk which

18:27.240 --> 18:32.680
has just happened we also want to support headless operations and since I know a lot of people are

18:32.680 --> 18:39.160
wondering yes we are bringing this to schematic in symbols no it's not in 9 basically we just ran

18:39.160 --> 18:44.440
out of time to do the necessary internal changes to the schematic editor to make that possible

18:45.480 --> 18:50.040
so if you want to learn more you can find a little bit more detail than I was able to cover today

18:50.040 --> 18:55.000
in the dev dox link here as well as more information about creating new API plugins

18:56.840 --> 19:02.600
Kika Python is up on Python package index so you can check that out and there's some examples

19:02.600 --> 19:11.640
basic plugins and also just some quick scripts in that repo so with that any questions

19:21.000 --> 19:35.480
Hi I was just wondering how does that work when you have multiple type of instance running

19:35.480 --> 19:41.480
like audio select one or stuff like that great question so the question was if you have multiple

19:41.480 --> 19:47.960
different instances how do you know which one to talk to so there will be a default path that the

19:47.960 --> 19:53.240
first instance will grab and then after that if it's already taken you know you will have a

19:53.240 --> 19:58.440
different way to communicate that will have a different you know process ID in the in the path

19:58.440 --> 20:03.640
essentially when you launch a plugin from P cad it passes the information through environment

20:03.640 --> 20:09.080
variables as to where you should communicate with this key cad that just launched it but if you

20:09.080 --> 20:14.280
are running from a debugger you would have to manually override that if you didn't want to use the

20:14.280 --> 20:18.920
default path so if you're if you're developing a Python plugin I recommend using just one

20:18.920 --> 20:28.680
instance at a time can you go a bit into can you go a bit into how the virtual environment

20:28.680 --> 20:36.920
installation works on a like a managed type installation yes so the virtual environment is today

20:37.480 --> 20:44.040
pretty basic and assumes one particular workflow which has so far been working in my tests but I

20:44.040 --> 20:49.800
know it won't cover all cases so basically if you're plugin in your plugin definition file

20:49.800 --> 20:55.560
you know says it's a Python plugin then we will look for a requirements text file and we will attempt

20:55.560 --> 21:02.440
to install so we will use Python basically you can configure which Python interpreter to use and then

21:02.440 --> 21:08.600
we will assume that we have access to the virtual environment module so if if you somehow don't have

21:08.680 --> 21:13.480
that it won't work and then we will attempt to install pip and then we will attempt to use pip to

21:13.480 --> 21:19.400
install your dependencies and if you can't install pip or if your dependencies don't have binary

21:19.400 --> 21:24.040
wheels it won't work and you'll have to do something manual but that's something that I'm sure

21:24.040 --> 21:34.440
could be improved in the future well we have more questions if our pod if you could start getting

21:35.240 --> 21:43.160
set up one question if my plugin is doing something both with schematics and PCB editor is

21:43.160 --> 21:48.840
a way that I can launch any application you mentioned that it has to be running in order to

21:48.840 --> 21:58.600
do understand to come on so if you want to have a plugin that launches kick out no I'm if my plugin

21:58.680 --> 22:09.640
it's like printing schematics and generating gorillas for example it has to deal with schematics

22:09.640 --> 22:18.760
and if one of them is not running once we happen you mentioned that schematics has to be running

22:18.760 --> 22:26.520
in order to understand commands for schematics yeah so today you can only with the with the current

22:26.520 --> 22:33.720
plugin system it's intended for the use case of the the user launches it from the editor so

22:34.520 --> 22:38.840
your plugin cannot open the editor the user has to open the editor and then launch the plugin

22:39.400 --> 22:44.280
in the future we won't have that restriction one of the things I put on the roadmap was a headless

22:44.280 --> 22:50.200
mode so right now you actually can't do plotting and exporting with this that's well supported by

22:50.200 --> 22:55.400
keycud CLI so that's our recommendation right now but in the future you will be able to do things

22:55.400 --> 23:01.080
like that through a special mode of keycud CLI where you can have your plugin say now I want to

23:01.080 --> 23:13.240
open this schematics file and work with it. Any further questions? Okay thank you John

