This is the third blog post in the Google Summer of Code 2026 series and serves as the final report. View the previous blog post here.
Well, it was a good summer, but as with all good things, it must come to an end eventually. Here is everything that I did and learned during my time as a GSoC contributor with the CNCF, working with Drasi and Dapr Agents to make it easier for developers to build business-event driven, autonomous agents (also known as “ambient” agents). This won’t be as fluid as the earlier blog posts as I need to tick off some boxes for the GSoC final report, but hopefully it’s still interesting.
Summary
My work spanned across the Dapr Agents and Drasi platform repositories. I’ve listed the tracking issues here that link to all of the relevant PRs, but there will also be references to the PRs in the project deep dive.
Link to Dapr Agents tracking issue: https://github.com/dapr/dapr-agents/issues/630
Link to Drasi tracking issue: https://github.com/drasi-project/drasi-platform/issues/435
Project deep dive
If you haven’t already, I highly recommend that you read the intro blog post and midterm blog post to understand the context behind the GSoC project, Drasi, Dapr Agents, and the terms used in this blog post. Just for you though, I’ll give a brief summary.
Background context
Interacting with “pure” LLMs is almost never done anymore — familiar tools like the web versions of Claude and ChatGPT have shifted to “conversational agents”, with memory to remember previous messages and tool calling to enrich themselves with relevant information. Conversational agents are the most visible kind of agent to consumers today, with use cases such as search queries, customer support, or troubleshooting.
However, what companies really want is to build autonomous agentic systems that can proactively handle business-critical processes and replace your job. For this to happen, agents must be able to run in the background (because nobody wants to babysit 24/7), run for a long time (since a lot of business process are complex), and escalate when necessary (very important). On top of that, while running autonomous agents in production, more issues pop up:
- Agents are bursty — they may execute for several minutes before waiting for approval for multiple days or weeks.
- Failures are common — when agents restart, they repeat LLM/tool calls, which can be expensive at scale.
- Governance and compliance — in highly-regulated industries, you need to be able to tightly control what an agent can access, and prove what an agent did at each step (and who authorized it) if you’re called up for an audit.
- Connecting to existing data sources and triggering agents from them involves tons of boilerplate code, reducing developer velocity.
Furthermore, these triggers are typically done in one of two ways:
- Polling data sources, which can be inefficient and can sometimes miss changes (or the lack of them)
- Long-lived connections, which are fragile and do not scale with traditional agent deployment models
Fortunately for them (and unfortunately for us), there are several CNCF projects in this space:
Drasi is a CNCF Sandbox project aimed at making detecting and reacting to changes across data sources easier via declarative configuration. It consists of three main components:
- Sources to ingest data from existing systems — databases, streaming platforms, webhooks from third-party platforms, and more.
- Continuous Queries that evaluate incoming data from different sources against user-defined, high-level “business conditions”, and emit “change” events when those conditions are satisfied.
- Reactions to push events to downstream consumers, or take action based on those events — this could be anything from updating dashboards, executing
kubectlcommands, or triggering agents.
All of these components are pluggable, allowing you to build your own connectors for the tech stack you use, and donate them to the community if you feel like others can benefit.

Dapr is a CNCF Graduated project consisting of a sidecar runtime and multiple APIs to help developers build microservices and distributed systems. One of its most popular and useful features is its built-in durable workflow engine (based on virtual actors), which powers the Dapr Agents agentic framework/subproject. Dapr Agents comes with many advantages over traditional agentic frameworks, but the one I find personally interesting is that agents can be “deactivated” (unloaded from memory) and reactivated on demand, allowing many agents can be multiplexed onto a single core all thanks to the virtual actor architecture. There’s nothing quite like it today.
As a quick demonstration of Dapr Agents’ capabilities, suppose we have three replicas of some document summarization agent app:

With Dapr Agents, we can easily trigger agents via pub/sub messages. The first task arrives, and one replica picks it up and schedules an agent (note: the agent doesn’t have to land on this replica, and the agent’s execution state or “progress” is managed by the sidecar; see the Dapr Workflow docs for more information).

The next task arrives, another replica picks it up and schedules an agent.

This continues until all of the tasks have been processed, with an agent for each task running on some replica.

At this point, some agents may become inactive (perhaps waiting for human approval). This means that they are unloaded from memory, freeing up resources for other potential agents to run.

Time passes, and our agents that were previously inactive have now become active again after receiving approval. Notice how they land on different replicas than the ones they were on originally — this is the “multiplexing” that was mentioned earlier. Some other agents have also become inactive.

Now, what if a replica inevitably fails?

The agents that were on that replica simply pick up from their last saved “checkpoint” on a new replica, as everything is backed by a durable store. Meanwhile, the other agents keep making progress.

If we’re using Kubernetes deployments, another pod/replica might be created since our desired replica count is three. Progress continues.

Some complete while the rest continue…

Finally, all of the agents complete.

Hopefully you have a better understanding now of how Dapr Agents works under the hood, how it can scale, and how it handles faults to enable long-running agents.
Now that you know the context behind Drasi and Dapr Agents, this GSoC project was focused on integrating the two projects to enable new use cases, requiring a lot of exploratory work and uncovering gaps in both projects. The following sections discuss the work that was done and the numerous challenges faced along the way.
Drasi extension for change-driven agents
After familiarizing myself with both projects’ architectures and learning about Kubernetes during the community bonding period, we decided that the first milestone would involve writing an extension for Dapr Agents so that developers can trigger agents with Drasi events. To start with, we assumed that the Drasi queries would be known in advance — while not ideal, this would help us discover any initial gaps and scope the work for the GSoC period appropriately.
To give you an idea of how this could be used in practice, pretend that we are an electronics retailer that wants to automate inventory management using agents that place orders when products become low in stock (lower than some threshold). Products already live in Postgres, but we don’t have an existing eventing system nor any agent infrastructure (this is a greenfield initiative). Yes, this can probably be done with a deterministic workflow, but this request comes straight from the top.
We end up with something like this:

At some point, a new graphics card “XYZ GPU” becomes available and is added to the product list. Drasi then captures the low-level change from Postgres, decodes it, then sends it to the query so it can update its state for “XYZ GPU”.

Later on, the stock level for “XYZ GPU” changes, which Drasi tracks. Notice that the stock level for “XYZ GPU” is still above the threshold, so the low stock condition has not been satisfied and no change event has been emitted by the query.

Some more time passes, and the stock level for “XYZ GPU” changes once more. This time, the stock level for “XYZ GPU” is falls below the threshold, so the low stock condition is met.

The query emits a change event in the shape that you defined in the query configuration, and eventually gets published by the Drasi pub/sub reaction.

Lastly, the inventory agent app pulls this event, translates it to an actionable task, then triggers the agent.

Most of this flow already existed — the main issue was it was not easy to subscribe to Drasi queries without a decent understanding of Drasi and Dapr Agents internals. In today’s world where time is limited and expectations are high, a good developer experience is extremely important.
Initially, we were thinking of a decorator @drasi_trigger allowing us to attach metadata (Drasi query ID, Dapr pub/sub component name, pub/sub topic name, etc.)
to the agent, and later use that metadata at runtime to create Dapr pub/sub subscriptions and filter on events as they arrive.
However, looking at the agent initialization flow, there was no easy way to place the decorator as all flows boiled down to something like:
agent = DurableAgent(...)
runner = AgentRunner()
try:
runner.serve(agent)
finally:
runner.shutdown(agent)
Because of this, we instead pivoted to lifecycle hooks (see this PR) so that we could have a callback to modify the agent
after initialization and before it is hosted as a service (i.e. the blocking serve() call). This way, we could not only preserve the existing agent code and initialization flow,
but we could also leverage some of the existing subscription creation code.
As a result, anyone using our extension wouldn’t have to learn a new paradigm as the initialization flow looked like:
agent = DurableAgent(...)
drasi_trigger(
agent,
query_id="at-risk-orders-query",
pubsub="pubsub",
topic="orders.at-risk",
)
runner = AgentRunner()
try:
runner.serve(agent)
finally:
runner.shutdown(agent)
While building out an end-to-end example, we had to make a decision: what would the event shapes be? Since we were reusing an existing Drasi “pub/sub router” reaction, the choice was between “packed” events representing multiple batched changes, “unpacked” events representing a single, discrete change, or both.
{
"queryId": "low-stock-event-query",
"sourceTimeMs": 18002672001,
"addedResults": [
{
"product": "XYZ GPU",
"stock": 3,
"threshold": 5
},
{
"product": "ABC Laptop",
"stock": 12,
"threshold": 25
},
{
"product": "123 Smart Glasses",
"stock": 1,
"threshold": 1
},
],
"updatedResults": [],
"deletedResults": [],
"sequence": 1
}{
"op": "u",
"ts_ms": 18002672001,
"seq": 1,
"payload": {
"source": {
"queryId": "low-stock-event-query",
"ts_ms": 18002672001
},
"after": {
"product": "XYZ GPU",
"stock": 3,
"threshold": 5
}
}
}To minimize scope creep, we focused on unpacked events for two reasons:
- Agents would have an easier time acting on individual changes.
- Common issues relating to multi-tenant architectures would be eliminated off the bat — data leakage, the “noisy neighbour” problem where one slow course of action blocks the others from completing, among others.
As a concrete example, imagine that you have an agent that is triggered when orders are delayed/at-risk and proactively resolves them. A packed event could contain multiple at-risk order records, each associated with a customer who holds a certain subscription tier. Premium subscription tiers would have different guarantees than basic subscription tiers, meaning that an agent would need to delegate to specialized subagents to avoid juggling many tasks (which still suffers from data leakage and the noisy neighbour problem without careful design). You might also have a custom enterprise tier for enterprise customers with different SLAs, which could force you to use unpacked events anyway.
Now that we could receive events, the next step was to be able to filter, validate, and transform them into a actionable task message before triggering the agent. Even before the GSoC period, I’d recognized that this would be a problem — Dapr’s content-based routing, is done by the Dapr sidecar for push-based subscriptions, but Dapr Agents recently migrated to pull-based subscriptions (probably for natural backpressure). This grunt work then had to be done in client code, but there was no support for it at the time. I opened an issue for client-side filtering, reviewed the eventual PR, and eventually added client-side transformation myself. We also decided that Drasi subscriptions should not share the same pub/sub topic used by the agent’s primary subscription as there was no way to deliver a single event (i.e. fan-out) to multiple subscription handlers at the application level (nor should it, it’s better suited to the workflow level since our focus is on business processes). This was a painful realization — I spent many hours trying to debug why Drasi events sometimes failed to trigger agents before figuring out that there was a race condition between the primary handler and the Drasi event handler.
After that, the core of the work was done, but we still had another decision to make as to who would own the models used to validate Drasi events.
Since they were autogenerated from JSON schemas on the Drasi side, it was natural to consume them as a part of a Drasi SDK.
Unfortunately, limitations with the autogeneration tool datamodel-codegen used by Drasi, as well as model name collisions due to how the JSON schema was defined
(see the entire diagnosis here) forced us to vendor (a fancy term for copy over) the schemas
to the extension, as otherwise we’d be blocked indefinitely trying to devise a clever workaround.
After tackling another race condition where tests would complete before agents could be scheduled to run, the initial extension was able to be merged and released.
Here’s a demo of the Drasi extension in action:
Exploring dynamic Drasi subscriptions for ambient agents
The second milestone for the GSoC period explored the idea of agents discovering Drasi queries at runtime, subscribing to them, then waiting for events to arrive and acting on them with dynamic, LLM-generated, context-specific “instructions”. The main benefit of this would be that agents and Drasi pipelines can be developed independently, and not having to redeploy agent apps when Drasi queries are updated. In addition, the agent would be able to “remind” itself about what to do with its generated “instructions”, which is useful for long-running tasks.
As this part of the project involved multiple services across different namespaces, we made sure to write a design document with the decisions and tradeoffs made. However, I’ll summarize the most interesting challenges here.
After some discussion, we agreed that a dedicated Drasi reaction/connector for routing events to agents (an “agent router”) was necessary, as the pub/sub router used in the previous milestone relied on declarative configuration (YAML) and had no concept of agent identity or support for agents. To allow the agent to subscribe, there needed to be an MCP server with tools, which we decided would be in-process as the tools would be specific to this reaction (and for simplicity).
We also needed to maintain some sort of subscription state in the reaction, as some agents may want only certain types of events for certain queries, yet we didn’t want agent developers to write one-off logic to filter out events. However, a simple in-memory store wouldn’t be enough for anything outside of local development or testing, so this needed to be backed by a durable store (we chose Dapr state stores as Drasi already relied on Dapr and to enable developers to swap in their preferred storage provider). One downside of this choice is that we can only support one replica without implementing some sort of cache invalidation, but that was a problem we figured we could deal with later down the line (hopefully).
The state model itself was influenced heavily by Dapr state store limitations — being a generic abstraction, it only supports key-value patterns. On top of that, when an event was emitted, we had to be able to look up all of the agents interested in that event with just the event itself and its metadata. While there are definitely some optimizations to be made (potentially using sorted lists), we ended up with a sort of “nested” map:
{
"query_id_1": {
"subscription_id_1": {...},
"subscription_id_2": {...},
"subscription_id_3": {...},
...
},
...
}
Next, we had to deal with fundamental distributed systems problems: delivery guarantees, consistency, and caching. We prioritized guaranteed delivery and strong consistency throughout for several reasons:
- Agents would be executing in the background — extra latency is not a problem since nobody is actively monitoring them.
- Our focus was on autonomous agents executing not just grunt work, but critical and/or customer-impacting business processes. Imagine what would happen if your agent never kicked off a critical action because an event was dropped due to network congestion, or failed to even be sent because a replica had stale subscriptions?
- The nature of the projects — Dapr Agents is designed for enterprise scale, while Drasi solves a specific problem for enterprises that want to act on changes across multiple, scattered data sources.
With guaranteed delivery, we needed to be able to handle duplicate messages/actions. On the reaction side, we made our subscription tool calls idempotent by treating subscriptions as “upserts” and having the agent pass in subscription identifiers. On the agent side, we wanted exactly-once semantics as otherwise we’d have duplicate events triggering duplicate workflows. Fortunately, Dapr Agents offered built-in deduplication in a 60 second window, which was good enough for us.
For consistency and caching, we decided on a cache-aside strategy for reads and a write-through strategy for writes to provide a balance between simplicity, read performance, and (local) consistency. We treated the backing store as the “source of truth”, ensuring that a subscription can never be lost by writing them to the backing store first before updating the in-memory cache. Under the assumption that subscription writes would be quite rare, we opted for optimistic concurrency control with Dapr’s support for ETags
Once we addressed the problems around the agent router, we needed to figure out the responsibilities of the agent and the agent runtime. Some of these challenges are extremely interesting as they were unique to our situation (from a non-biased perspective).
The first problem relates to subscriptions — we’ve already ensured that subscriptions can never be lost once recorded, but how do we ensure that a subscription request gets delivered? This is where the agent runtime comes into play, as Dapr’s MCP client has retries built-in.
The second problem relates to data consistency across services. For example, say the agent decides to subscribe and fires off a tool call to the agent router, which successfully persists the subscription and sends a response.
If that response is lost for whatever reason, there is a window where the agent router could forward an event to the agent without the agent having any record of the subscription (as it hasn’t retried and received a successful response),
resulting in this “indeterminate” state. To address this, we implemented a “two-stage” subscription — the agent runtime would persist its own subscription record with a "PENDING" status before calling the subscription tool.
Any event that arrived after that point would be handled as there would be a subscription record, and the runtime would mark the subscription as "ACTIVE" on a successful response.
This, along with the recent introduction of Sessionless MCP via Explicit State Handles, cemented our decision to have client-created subscription IDs (which is atypical).
A third problem we faced was that subscription ID and agent ID are runtime concerns, and the LLM should not be responsible for generating those (for good reasons). However, the agent router must obtain them somehow for its own subscription state, so we needed a way to “inject” these into MCP tool calls without exposing them to the LLM.
Aside — if you aren’t familiar with MCP, it’s effectively a protocol that standardizes the way agents call APIs. Most use cases follow the request-response model, where requests and responses are structured JSON that LLMs are all familiar with. MCP tools are functions that are roughly equivalent to your API routes in a typical web server, but instead of being identified by a path, tools are identified by tool names (which are part of a tool schema).
As MCP is continuously evolving, best practices have not been established yet for injecting runtime arguments.
Some MCP servers accept a _meta property that serves a similar purpose as HTTP headers at the connection level,
but we opted to keep our injected arguments (subscription ID, agent ID) at the top level.
Another problem dealt with “reminding” the agent when the Drasi event is received via dynamic, LLM-generated instructions. Our thought process going in was effectively: “When the LLM decides to subscribe, it should be able to determine what it should do to act on an incoming event. Can’t we just have instructions as a regular MCP tool parameter with a detailed description?” This sounded reasonable enough at the time (apart from the meta prompting required), but we quickly realized that instructions was a agent-only concern and should not be sent as part of the tool call. Accounting for injected arguments, this meant that we had to maintain two different schemas for our subscription tool:
LLM-exposed tool schema: { query ID, event types, instructions }
Agent router tool schema: { query ID, event types, agent ID, subscription ID }
Once we knew how to generate the instructions, we had to consider the best place to store and inject those instructions. A natural direction was to leverage the system prompt/instructions, since Dapr Agents already supported “hot-reloading” for it (allowing changes to be made at runtime with zero downtime), but this was discarded. To understand why this was insufficient, we need to look at how Dapr agents are deployed. In our case, a pod holds an agent app, or “worker host” that can host many logical agents (instances) for a given type (if you’re interested, you can read up on how the Dapr workflow substrate scales here). Modifying the instructions would affect every agent belonging to that type, so it was decided that instructions would be a part of the runtime subscription state.
For instruction injection, we relied on our initial idea of an agent subscribing, “sleep” (deactivate), and “wake up” (reactivate) on events to help guide us. To “wake up” the agent, we could either route the event to the same agent instance, potentially resulting in “eternal” agents with bloated context windows and massive history logs; or we could effectively continue the workflow on a new agent instance since all the information needed to look up subscription state would exist on the event (namely CloudEvent metadata). We ultimately went with the second approach due to the downsides of the first approach and because no functionality exists in Dapr Agents today to handle the first approach, but this is still up in the air (again, there are no best practices to follow).
The exact implementation details can be found in this PR, but I won’t delve any further since this blog post is long enough as is.
Here’s a rough sequence diagram for the subscription flow:

Cloud Native Vancouver July 2026 meetup presentation
As a fun little “sidequest”, I delivered a talk about Drasi and Dapr Agents at my local CNCF chapter around the time the initial Drasi extension was being polished for release. I hadn’t done a technical presentation before, and I knew it would be challenging to introduce two CNCF projects and talk about the GSoC project in 30 minutes. Thankfully, I had the help of my mentor Aman Singh (who’s done this many times) for helping me cut down the slides, figuring out timings and structure, and reviewing my notes for accuracy. The talk went quite well despite my nervousness — I was able to answer most of the questions and I got some great feedback from the audience on how to deliver a more engaging and focused presentation (thanks to all!). These were:
- Preferring one motivating example and referencing that throughout the talk and the demo
- Preferring live demos (even if they break) over recorded demos
- Preferring QR codes over links so people can scan them on the spot I’m not entirely satisfied with how I presented either — I relied a lot on my notes as there was a lot of content to cover, but this anchored me to my laptop and made the talk feel less natural than I would’ve liked.
All things said, I really enjoyed presenting. While it’s not something I’d personally want to do every single day, sharing my knowledge and learnings from working on a cool project in an emerging field is rewarding. I hope to be able to present at more meetups and potentially bigger conferences like KubeCon + CloudNativeCon or the new AGNTCon + MCPCon in the future.
Link to slides: https://docs.google.com/presentation/d/1YVNf-c2Pl3h1JQTcViRoS2Hp4OTvh_zzgJa9h-ouSV4/edit?usp=sharing
What I learned
Here’s what I’ve learned from working on my project and observing how other engineers operate on the Drasi and Dapr projects. Some of this may be specific to open-source work rather than traditional corporate/product work, but I hope that some of this advice will be useful to students and newcomers to the industry.
- Write down everything — your action items for today, error logs and steps you took while debugging, repeated shell commands. As someone new to the industry, you need to know so much that your brain simply can’t hold it all.
- Do your research — AI is useful in that you don’t even need to know the right terminology or write perfectly coherent thoughts. For example, when I was wrestling with Python package management to be able to publish the Drasi extension as a separate package yet have it as part of a monorepo, it helped explain to me how module resolution works despite me likely misusing a bunch of terms (unfortunately I’ve forgotten how it works now).
- Use AI judiciously — this might be partially due to necessity since I couldn’t afford to burn through that many credits, but as someone who is relatively inexperienced, you should still take some time to write code by hand as it forces you to slow down and think about design principles, edge case handling, error handling, and other foundation skills. Reviewing AI-generated code is not the same — even if you scrutinize every line, how do you catch these things without having thought about it or experienced it yourself? Sure, you could plan for every failure mode, but that again requires experience (unless you’re a prodigy). That said, I did leverage it extensively for prototyping and work involving lots of boilerplate (e.g. tests), as the stakes are much lower there.
- Make life easier for other people — this comes in muliple forms such as communicating frequently (this is usually asynchronous), pointing out questionable areas on PRs, preparing discussion points before meetings, and trying to unblock yourself as much as possible. With higher productivity expectations nowadays due to AI, people are stretched thin, so removing some of this burden is highly appreciated.
- Senior/staff engineers aren’t gods — they will make mistakes, backtrack on earlier decisions once they have more information, and disagree with each other. What matters is having a breadth of knowledge, depth in a domain or two, the ability to navigate ambiguity, adapt to changing priorities, and being able to find and take ownership of high-impact projects, across teams if necessary (for Drasi and Dapr this involves working across multiple codebases — core runtime, client libraries/language SDKs, frameworks and integrations). This means that the dreaded soft skills are equal to or arguably more important than technical skills as you need to be able to advocate for yourself and your work, no matter what it is.
- Most importantly, it’s ok to not know what you’re doing — I’m not exaggerating when I say that I woke up most days not knowing what I needed to do that day because of all of the ambiguity. This is why it’s important to identify your daily/weekly goals, and how they relate to the big picture before you break them down into daily tasks.
Future work
So far, v0.1.0 for the Drasi extension has been published with the ability to statically subscribe to Drasi queries. There’s also a very rough proof of concept of an “agent-aware” Drasi event router with an MCP server. This allows agents to subscribe to Drasi queries dynamically over any Dapr-supported message broker, and there’s another proof of concept demonstrating how Dapr Agents developers can enable this capability with a handful of lines of code.
As school is starting up again, my mentor Aman Singh will pick up from where I left off and create an MVP based on my work, but there are definitely some things that I would like to explore in the future to make things production-ready (note: this is non-exhaustive):
- How can agent skills be integrated? I don’t think this would replace persisted subscription instructions as we need to guarantee that a new agent instance “sees” these instructions (by always loading them into its context), but this could make the “meta prompts” reusable and allow individual agent instances to carry out different segments of a long-running, domain-specific workflow.
- Security was out of scope for the GSoC period not only because of time limitations, but because agent identity is a relatively new problem.
- Scale-to-zero for agent apps (not to be confused with the agents themselves) had to be cut as well due to a lack of Dapr runtime support (you can see some related proposals and issues).
- Finally, we focused on use cases that could probably be modelled by deterministic workflows (e.g. a basic inventory agent that orders more stock when a product in a database becomes low in stock). Exploring use cases involving investigation/synthesis that leverage Drasi’s advantages (detecting high-frequency changes and the absence of change) and Dapr Agents’ advantages (adding reliability, scalability, durability, and governance to long-running autonomous agents and orchestrations) could expose interesting gaps.
Acknowledgements
Of course, all of this wouldn’t have occurred without the efforts of many organizations and individuals in the name of advancing open source. Thank you to Google and the GSoC team for providing this amazing structured and paid program, allowing contributors to fully immerse themselves into their communities and projects. Thank you to the CNCF for helping to foster these amazing cloud-native open-source projects, and especially Nate Waddington and the rest of the CNCF Mentoring team for handling logistics and behind-the-scenes work. Thank you to Microsoft Azure and the Office of the CTO Incubations team for ideating Dapr and Drasi — I’ve learned how to think about the developer and operator experience when building tools, which is challenging yet fulfilling.
Lastly, I want to give a personal thank you to my mentors Aman Singh and Casper Nielsen for helping me to grow as a developer and open-source contributor. Without them, this project would not have been successful or challenging (in a good way). Apart from biweekly syncs and reviewing PRs, they gave me the day-to-day autonomy to make feature-level design choices and tradeoffs, and identify gaps in Drasi and Dapr Agents that needed to be addressed for the project (as long as I was able to justify them). However, due to my inexperience with system design and this particular niche (the intersection of AI, cloud, durable execution, and event-driven systems), the ambiguity was overwhelming at certain times, so I’m thankful that they helped to steer the ship by answering questions and collaborating together on design documents.
How to get involved
Join the Dapr discord, raise an issue in the Dapr Agents repository, or learn how to contribute to the Drasi extension. I will try to be as active as possible by reviewing PRs for Dapr Agents and answering questions in the Discord server.
To learn more about Drasi, join the Drasi discord, view the documentation, or try out some of the tutorials.