[{"data":1,"prerenderedAt":2503},["ShallowReactive",2],{"$4vggmDfAaE":3,"home_ai_posts":94},{"id":4,"title":5,"body":6,"contact":7,"description":6,"extension":26,"hero":27,"lab":33,"meta":47,"navigation":50,"path":51,"projects":52,"seo":83,"stem":84,"techstack":85,"__hash__":93},"index\u002Findex.yml","Made Yoga Mahardika | Software Engineer .NET Nuxt",null,{"email":8,"links":9},"madeybog@gmail.com",[10,14,18,22],{"title":11,"icon":12,"url":13},"Youtube","i-simple-icons-youtube","https:\u002F\u002Fwww.youtube.com\u002F@madey02",{"title":15,"icon":16,"url":17},"Tiktok","i-simple-icons-tiktok","https:\u002F\u002Fwww.tiktok.com\u002F@boggg_",{"title":19,"icon":20,"url":21},"Github","i-simple-icons-github","https:\u002F\u002Fgithub.com\u002Fmadeyoga",{"title":23,"icon":24,"url":25},"Linkedin","i-simple-icons-linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fmade-mahardika-4a205a379\u002F","yml",{"intro":28,"title":29,"location":30,"links":31},"Hey, I'm Made Yoga.","[Hey, I'm Made Yoga.]{.text-primary} Fullstack Software Developer.","Samarinda, Indonesia",[32],{"icon":20,"url":21},[34,39,43],{"title":35,"status":36,"description":37,"link":38},"Hermes Agent Bot Mode","shipping","Three specialist bots (Blogi, Nuxti, Aspi) on Hermes Agent Bot Mode: skills, MCPs, and how they hand work off.","\u002Fblog\u002Fhermes-bot-mode",{"title":40,"status":36,"description":41,"link":42},"Hermes Agent + DeepSeek","Daily-driver AI coding agent setup for ASP.NET Core and Nuxt: skills, MCP servers, and workflows that actually speed up backend work.","\u002Fblog\u002Fai-agent-workflow-deepseek-hermes",{"title":44,"status":45,"description":46},"Cursor-assisted development","exploring","Using Cursor as a pair-programming environment for portfolio work, content, and .NET library iteration. Figuring out what sticks in a real workflow.",{"sitemap":48},{"lastmod":49},"2026-08-19",true,"\u002F",[53],{"slug":54,"title":55,"category":56,"description":57,"link":58,"repo":59,"docs":58,"image":60,"techstack":61,"features":71},"authendpoints","AuthEndpoints","opensource","A composable auth endpoints library for ASP.NET Core. Registration, login, 2FA, password reset, and passkeys, bootstrapped in minutes.","https:\u002F\u002Fmadeyoga.github.io\u002FAuthEndpoints\u002F","https:\u002F\u002Fgithub.com\u002Fmadeyoga\u002FAuthEndpoints","\u002Fimages\u002Fauthendpoints-3-0-rc.png",[62,65,68],{"icon":63,"title":64},"i-simple-icons-dotnet",".NET",{"icon":66,"title":67},"i-simple-icons-csharp","C#",{"icon":69,"title":70},"i-simple-icons-nuget","NuGet",[72,75,77,79,81],{"icon":73,"title":74},"i-lucide-check","Composable auth endpoints & modules",{"icon":73,"title":76},"Cookie, bearer, or Simple JWT sign-in",{"icon":73,"title":78},"Passkeys (WebAuthn) support",{"icon":73,"title":80},"Hardening on by default",{"icon":73,"title":82},"Optional GitHub & Google OAuth",{"title":5},"index",[86,87,90],{"title":64,"icon":63},{"title":88,"icon":89},"Django","i-vscode-icons-file-type-django",{"title":91,"icon":92},"Nuxt","i-vscode-icons-file-type-nuxt","_vYesE7anynnUOpMWgufdqTeSsMvqZ3hPUTZeqV88do",[95,989,1649,1933],{"id":96,"title":97,"authors":98,"badge":103,"body":104,"date":970,"description":971,"extension":972,"image":973,"meta":974,"navigation":50,"path":984,"seo":985,"stem":987,"__hash__":988},"posts\u002Fblog\u002F5-years-of-django-pros-and-cons.md","What 5 Years with Django Taught Me: Pros and Cons",[99],{"name":100,"to":51,"avatar":101},"Made Y",{"src":102},"\u002Fimages\u002Fprofile2.jpg",{"label":88},{"type":105,"value":106,"toc":954},"minimark",[107,112,116,120,133,136,139,142,202,206,211,214,480,484,487,845,849,859,863,867,870,874,878,881,899,906,909,913,916,928,932,935,939,942,945,951],[108,109,111],"h2",{"id":110},"introduction","Introduction",[113,114,115],"p",{},"In this article, I'll share my real-world experience after 5 years of working with Django, from small side projects to production web apps. Whether you're just starting with Django or considering it for your next project, I hope this helps you understand what's great about it, and where it can get tricky.",[108,117,119],{"id":118},"why-i-chose-django-in-the-first-place","Why I Chose Django in the First Place",[113,121,122,123,132],{},"I started my web development journey in PHP, learning CodeIgniter during an internship at ",[124,125,131],"a",{"className":126,"href":128,"rel":129},[127],"text-primary","https:\u002F\u002Ftorodeveloper.com\u002F",[130],"nofollow","Toro Developer Universal"," in 2018. My main task was to develop a module and UI to automatically generate CRUD operations from existing sql tables. It was a great learning experience, but while working on it, I discovered that Django, a Python framework I'd barely heard of at the time, already had this functionality built in through the Django ORM and Admin. That caught my attention.",[113,134,135],{},"After the internship ended, I decided to explore Django on my own. At first, it was just curiosity. But later, while studying data science and machine learning at university, I was assigned a class project: build a handwriting character recognition model. Using TensorFlow and the Keras API and Python, I trained a model that could take an image of handwritten text and predict the letters.",[113,137,138],{},"When my lecturer asked me to showcase the project through a website, Django instantly came to mind. It gave me exactly what I needed: a way to build both the backend API to run predictions and a simple UI for users to upload images, all in one framework.",[113,140,141],{},"By the end of that project, I had a site where people could upload an image, the server would load my trained model, and the prediction results would appear right on the screen. Since then, I've used Django to build a variety of applications, from a blogging platform where people can sign up and share their stories, to a point-of-sale system with dashboard analytics, customized Django Admin, invoicing, and inventory management that runs entirely on a store's local network, connecting everyone from cashiers to storage staff. I've also built online stores and catalogs, and through each project, Django has remained my go-to framework for turning ideas into fully functional software.",[143,144,145,157,180],"tabs",{},[146,147,150],"div",{"icon":148,"label":149},"i-lucide-bar-chart-4","Customized Django Admin Dashboard",[113,151,152],{},[153,154],"img",{"alt":155,"src":156},"customized django admin dashboard","\u002Fimages\u002Fchrome_2025-07-24_14-44-25.jpg",[146,158,161],{"icon":159,"label":160},"i-lucide-shopping-cart","Online Store",[162,163,164,172],"pictures",{},[146,165,166],{},[113,167,168],{},[153,169],{"alt":170,"src":171},"superjaya.id catalog","https:\u002F\u002Fres.cloudinary.com\u002Fdhqbr2d4l\u002Fimage\u002Fupload\u002Fv1755144296\u002FSJ1_oztatv.jpg",[146,173,174],{},[113,175,176],{},[153,177],{"alt":178,"src":179},"superjaya.id cart ui","\u002Fimages\u002FSJ2.jpeg",[146,181,184],{"icon":182,"label":183},"i-simple-icons-blogger","Blogging Platform",[162,185,186,194],{},[146,187,188],{},[113,189,190],{},[153,191],{"alt":192,"src":193},"xamarind blogging platform","https:\u002F\u002Fres.cloudinary.com\u002Fdhqbr2d4l\u002Fimage\u002Fupload\u002Fv1755150579\u002Fxamarind1_k8uvjt.webp",[146,195,196],{},[113,197,198],{},[153,199],{"alt":200,"src":201},"xamarind blogging platform article page","https:\u002F\u002Fres.cloudinary.com\u002Fdhqbr2d4l\u002Fimage\u002Fupload\u002Fv1755150579\u002Fxamarind2_w2dnvj.webp",[108,203,205],{"id":204},"the-good-stuff-about-django-pros","The Good Stuff About Django (Pros)",[207,208,210],"h3",{"id":209},"_1-django-orm","1. Django ORM",[113,212,213],{},"One of my favorite things about Django is the ORM. It lets you work with the database without writing raw SQL, and you can also run Python scripts during migrations. This came in handy more than once. Especially when I needed to populate a newly added column with default values right as the migration ran.",[215,216,221],"pre",{"className":217,"code":218,"language":219,"meta":220,"style":220},"language-python shiki shiki-themes material-theme-lighter github-light github-dark monokai","from django.db import migrations\n\ndef populate_default_status(apps, schema_editor):\n    MyModel = apps.get_model('myapp', 'MyModel')\n    MyModel.objects.filter(status__isnull=True).update(status='pending')\n\nclass Migration(migrations.Migration):\n    dependencies = [\n        ('myapp', '0001_initial'),\n    ]\n    operations = [\n        migrations.RunPython(populate_default_status),\n    ]\n\n","python","",[222,223,224,250,256,283,327,378,383,406,417,441,447,457,475],"code",{"__ignoreMap":220},[225,226,229,233,237,241,244,247],"span",{"class":227,"line":228},"line",1,[225,230,232],{"class":231},"sRxSC","from",[225,234,236],{"class":235},"ss--_"," django",[225,238,240],{"class":239},"swvn1",".",[225,242,243],{"class":235},"db ",[225,245,246],{"class":231},"import",[225,248,249],{"class":235}," migrations\n",[225,251,253],{"class":227,"line":252},2,[225,254,255],{"emptyLinePlaceholder":50},"\n",[225,257,259,263,267,270,274,277,280],{"class":227,"line":258},3,[225,260,262],{"class":261},"srJo8","def",[225,264,266],{"class":265},"sD0ED"," populate_default_status",[225,268,269],{"class":239},"(",[225,271,273],{"class":272},"sW6vx","apps",[225,275,276],{"class":239},",",[225,278,279],{"class":272}," schema_editor",[225,281,282],{"class":239},"):\n",[225,284,286,289,293,296,298,302,304,308,312,314,316,319,322,324],{"class":227,"line":285},4,[225,287,288],{"class":235},"    MyModel ",[225,290,292],{"class":291},"sGXK2","=",[225,294,295],{"class":235}," apps",[225,297,240],{"class":239},[225,299,301],{"class":300},"sAZ-3","get_model",[225,303,269],{"class":239},[225,305,307],{"class":306},"siCPE","'",[225,309,311],{"class":310},"sLACW","myapp",[225,313,307],{"class":306},[225,315,276],{"class":239},[225,317,318],{"class":306}," '",[225,320,321],{"class":310},"MyModel",[225,323,307],{"class":306},[225,325,326],{"class":239},")\n",[225,328,330,333,335,339,341,344,346,350,352,356,359,362,364,367,369,371,374,376],{"class":227,"line":329},5,[225,331,332],{"class":235},"    MyModel",[225,334,240],{"class":239},[225,336,338],{"class":337},"squCx","objects",[225,340,240],{"class":239},[225,342,343],{"class":300},"filter",[225,345,269],{"class":239},[225,347,349],{"class":348},"sQgqH","status__isnull",[225,351,292],{"class":291},[225,353,355],{"class":354},"sMTiH","True",[225,357,358],{"class":239},").",[225,360,361],{"class":300},"update",[225,363,269],{"class":239},[225,365,366],{"class":348},"status",[225,368,292],{"class":291},[225,370,307],{"class":306},[225,372,373],{"class":310},"pending",[225,375,307],{"class":306},[225,377,326],{"class":239},[225,379,381],{"class":227,"line":380},6,[225,382,255],{"emptyLinePlaceholder":50},[225,384,386,389,393,395,399,401,404],{"class":227,"line":385},7,[225,387,388],{"class":261},"class",[225,390,392],{"class":391},"sKvfc"," Migration",[225,394,269],{"class":239},[225,396,398],{"class":397},"sW3Pz","migrations",[225,400,240],{"class":239},[225,402,403],{"class":397},"Migration",[225,405,282],{"class":239},[225,407,409,412,414],{"class":227,"line":408},8,[225,410,411],{"class":235},"    dependencies ",[225,413,292],{"class":291},[225,415,416],{"class":239}," [\n",[225,418,420,423,425,427,429,431,433,436,438],{"class":227,"line":419},9,[225,421,422],{"class":239},"        (",[225,424,307],{"class":306},[225,426,311],{"class":310},[225,428,307],{"class":306},[225,430,276],{"class":239},[225,432,318],{"class":306},[225,434,435],{"class":310},"0001_initial",[225,437,307],{"class":306},[225,439,440],{"class":239},"),\n",[225,442,444],{"class":227,"line":443},10,[225,445,446],{"class":239},"    ]\n",[225,448,450,453,455],{"class":227,"line":449},11,[225,451,452],{"class":235},"    operations ",[225,454,292],{"class":291},[225,456,416],{"class":239},[225,458,460,463,465,468,470,473],{"class":227,"line":459},12,[225,461,462],{"class":235},"        migrations",[225,464,240],{"class":239},[225,466,467],{"class":300},"RunPython",[225,469,269],{"class":239},[225,471,472],{"class":300},"populate_default_status",[225,474,440],{"class":239},[225,476,478],{"class":227,"line":477},13,[225,479,446],{"class":239},[207,481,483],{"id":482},"_2-django-management-commands","2. Django Management Commands",[113,485,486],{},"Management commands feel like little superpowers baked into the framework. They let me run Python scripts directly inside the Django environment, which is perfect for tasks like populating fields, importing \u002F exporting data, fixing incorrect values, or even creating quick backups. Whenever I need to tweak or move data, management commands are my go-to tool. For example, here's a management command that generates slugs for any blog post that doesn't have one:",[215,488,490],{"className":217,"code":489,"language":219,"meta":220,"style":220},"# blog\u002Fmanagement\u002Fcommands\u002Ffix_missing_slug.py\n\n# python manage.py fix_missing_slug\n\nfrom django.core.management.base import BaseCommand\nfrom django.utils.text import slugify\nfrom blog.models import Article\n\n\nclass Command(BaseCommand):\n    help = \"Generate slugs for articles that don't have one yet\"\n\n    def handle(self, *args, **options):\n        articles_without_slug = Article.objects.filter(slug__isnull=True)\n\n        for article in articles_without_slug:\n            article.slug = slugify(article.title)\n            article.save()\n            self.stdout.write(self.style.SUCCESS(f\"Slug set for: {article.title}\"))\n\n        self.stdout.write(self.style.SUCCESS(\"Done!\"))\n\n",[222,491,492,498,502,507,511,537,558,575,579,583,597,615,619,651,681,686,704,732,745,803,808],{"__ignoreMap":220},[225,493,494],{"class":227,"line":228},[225,495,497],{"class":496},"ss7Ak","# blog\u002Fmanagement\u002Fcommands\u002Ffix_missing_slug.py\n",[225,499,500],{"class":227,"line":252},[225,501,255],{"emptyLinePlaceholder":50},[225,503,504],{"class":227,"line":258},[225,505,506],{"class":496},"# python manage.py fix_missing_slug\n",[225,508,509],{"class":227,"line":285},[225,510,255],{"emptyLinePlaceholder":50},[225,512,513,515,517,519,522,524,527,529,532,534],{"class":227,"line":329},[225,514,232],{"class":231},[225,516,236],{"class":235},[225,518,240],{"class":239},[225,520,521],{"class":235},"core",[225,523,240],{"class":239},[225,525,526],{"class":235},"management",[225,528,240],{"class":239},[225,530,531],{"class":235},"base ",[225,533,246],{"class":231},[225,535,536],{"class":235}," BaseCommand\n",[225,538,539,541,543,545,548,550,553,555],{"class":227,"line":380},[225,540,232],{"class":231},[225,542,236],{"class":235},[225,544,240],{"class":239},[225,546,547],{"class":235},"utils",[225,549,240],{"class":239},[225,551,552],{"class":235},"text ",[225,554,246],{"class":231},[225,556,557],{"class":235}," slugify\n",[225,559,560,562,565,567,570,572],{"class":227,"line":385},[225,561,232],{"class":231},[225,563,564],{"class":235}," blog",[225,566,240],{"class":239},[225,568,569],{"class":235},"models ",[225,571,246],{"class":231},[225,573,574],{"class":235}," Article\n",[225,576,577],{"class":227,"line":408},[225,578,255],{"emptyLinePlaceholder":50},[225,580,581],{"class":227,"line":419},[225,582,255],{"emptyLinePlaceholder":50},[225,584,585,587,590,592,595],{"class":227,"line":443},[225,586,388],{"class":261},[225,588,589],{"class":391}," Command",[225,591,269],{"class":239},[225,593,594],{"class":397},"BaseCommand",[225,596,282],{"class":239},[225,598,599,603,606,609,612],{"class":227,"line":449},[225,600,602],{"class":601},"sMLJd","    help",[225,604,605],{"class":291}," =",[225,607,608],{"class":306}," \"",[225,610,611],{"class":310},"Generate slugs for articles that don't have one yet",[225,613,614],{"class":306},"\"\n",[225,616,617],{"class":227,"line":459},[225,618,255],{"emptyLinePlaceholder":50},[225,620,621,624,627,629,633,635,638,641,643,646,649],{"class":227,"line":477},[225,622,623],{"class":261},"    def",[225,625,626],{"class":265}," handle",[225,628,269],{"class":239},[225,630,632],{"class":631},"sDdYn","self",[225,634,276],{"class":239},[225,636,637],{"class":291}," *",[225,639,640],{"class":272},"args",[225,642,276],{"class":239},[225,644,645],{"class":291}," **",[225,647,648],{"class":272},"options",[225,650,282],{"class":239},[225,652,654,657,659,662,664,666,668,670,672,675,677,679],{"class":227,"line":653},14,[225,655,656],{"class":235},"        articles_without_slug ",[225,658,292],{"class":291},[225,660,661],{"class":235}," Article",[225,663,240],{"class":239},[225,665,338],{"class":337},[225,667,240],{"class":239},[225,669,343],{"class":300},[225,671,269],{"class":239},[225,673,674],{"class":348},"slug__isnull",[225,676,292],{"class":291},[225,678,355],{"class":354},[225,680,326],{"class":239},[225,682,684],{"class":227,"line":683},15,[225,685,255],{"emptyLinePlaceholder":50},[225,687,689,692,695,698,701],{"class":227,"line":688},16,[225,690,691],{"class":231},"        for",[225,693,694],{"class":235}," article ",[225,696,697],{"class":231},"in",[225,699,700],{"class":235}," articles_without_slug",[225,702,703],{"class":239},":\n",[225,705,707,710,712,715,717,720,722,725,727,730],{"class":227,"line":706},17,[225,708,709],{"class":235},"            article",[225,711,240],{"class":239},[225,713,714],{"class":337},"slug",[225,716,605],{"class":291},[225,718,719],{"class":300}," slugify",[225,721,269],{"class":239},[225,723,724],{"class":300},"article",[225,726,240],{"class":239},[225,728,729],{"class":337},"title",[225,731,326],{"class":239},[225,733,735,737,739,742],{"class":227,"line":734},18,[225,736,709],{"class":235},[225,738,240],{"class":239},[225,740,741],{"class":300},"save",[225,743,744],{"class":239},"()\n",[225,746,748,752,754,757,759,762,764,766,768,771,773,776,778,781,784,788,790,792,794,797,800],{"class":227,"line":747},19,[225,749,751],{"class":750},"sSsL9","            self",[225,753,240],{"class":239},[225,755,756],{"class":337},"stdout",[225,758,240],{"class":239},[225,760,761],{"class":300},"write",[225,763,269],{"class":239},[225,765,632],{"class":750},[225,767,240],{"class":239},[225,769,770],{"class":337},"style",[225,772,240],{"class":239},[225,774,775],{"class":300},"SUCCESS",[225,777,269],{"class":239},[225,779,780],{"class":261},"f",[225,782,783],{"class":310},"\"Slug set for: ",[225,785,787],{"class":786},"sYThS","{",[225,789,724],{"class":300},[225,791,240],{"class":239},[225,793,729],{"class":337},[225,795,796],{"class":786},"}",[225,798,799],{"class":310},"\"",[225,801,802],{"class":239},"))\n",[225,804,806],{"class":227,"line":805},20,[225,807,255],{"emptyLinePlaceholder":50},[225,809,811,814,816,818,820,822,824,826,828,830,832,834,836,838,841,843],{"class":227,"line":810},21,[225,812,813],{"class":750},"        self",[225,815,240],{"class":239},[225,817,756],{"class":337},[225,819,240],{"class":239},[225,821,761],{"class":300},[225,823,269],{"class":239},[225,825,632],{"class":750},[225,827,240],{"class":239},[225,829,770],{"class":337},[225,831,240],{"class":239},[225,833,775],{"class":300},[225,835,269],{"class":239},[225,837,799],{"class":306},[225,839,840],{"class":310},"Done!",[225,842,799],{"class":306},[225,844,802],{"class":239},[207,846,848],{"id":847},"_3-the-django-admin","3. The Django Admin",[113,850,851,852,858],{},"This is what first caught my attention back in my CodeIgniter days. Django can turn your models into a fully functional CRUD interface instantly. It's incredibly useful for development and testing, but it's not just for that; I've built entire internal tools with customized Django Admin. With the right tweaks (and a little help from packages like ",[124,853,857],{"className":854,"href":855,"rel":856},[127],"https:\u002F\u002Funfoldadmin.com\u002F",[130],"Django Unfold"," for a modern UI), you can make it both powerful and beautiful. It makes building apps with an administration fast and efficient.",[113,860,861],{},[153,862],{"alt":155,"src":156},[207,864,866],{"id":865},"_4-time-to-market","4. Time to market",[113,868,869],{},"When people talk about rapid development, Django is one of the few frameworks that actually delivers. Between the admin, ORM, and built-in features, I can go from idea to a working prototype in a fraction of the time it would take with many other stacks. It truly comes \"batteries included\": authentication, forms, and user management are already there out of the box. And when I've needed something more specialized, like APIs, or payments, the community has always had excellent, battle-tested libraries ready to go. Whatever the challenge, there's almost always a solution at hand.",[108,871,873],{"id":872},"the-not-so-great-parts-cons-of-django","The Not-So-Great Parts (Cons of Django)",[207,875,877],{"id":876},"_1-the-spoiled-kid-effect","1. The \"Spoiled Kid\" Effect",[113,879,880],{},"Spending years with a highly opinionated framework like Django made me a little spoiled. I realized this when I had to learn another (more barebone) web framework for work, ASP.NET Core. Django (and Python in general) spoils you with free, open-source, maintained community libraries for almost anything you can imagine. In contrast, you might not even find a library that does exactly what you need; and if you do, there's a chance it's freemium or commercial, which makes you appreciate Django's open-source ecosystem even more. It's not Django's fault, but it does make switching stacks a bit of a shock.",[882,883,884,887],"picture-and-caption",{},[113,885,886],{},"\"Where batteries?\"",[888,889,890],"template",{"v-slot:image":220},[113,891,892],{},[153,893],{"alt":894,"src":895,"className":896},"caveman","https:\u002F\u002Fi.kym-cdn.com\u002Fentries\u002Ficons\u002Foriginal\u002F000\u002F038\u002F301\u002Fcavemancover.jpg",[897,898],"rounded-lg","my-0",[113,900,901,902,905],{},"Another frustration comes when I need to run quick, one-off tasks. In Django, I can whip up a management command, drop it into my app, and run it inside the full project environment with a simple ",[222,903,904],{},"python manage.py mycommand",". It's effortless. Everything loads with the same settings, database, and context I already use. In a more barebone web framework like ASP.NET Core, there's no such luxury. I often end up creating clunky python scripts, console apps, or temporarily jamming code into controllers just to execute a simple job. Once you've lived with Django's workflow, you really feel the pain of not having it elsewhere.",[113,907,908],{},"And then there's the setup. Django's \"batteries-included\" approach spoils you so much that working without it feels exhausting. Authentication, ORM, admin, migrations, they're all just there in Django. But in a more barebone web framework, I suddenly find myself wiring up middleware, configuring dependency injection, and hunting for packages just to get to the same baseline Django gives me on day one. Once you've been spoiled by Django's defaults, going back to the \"manual labor\" world of other frameworks is a real test of patience.",[207,910,912],{"id":911},"_2-performance-or-the-reputation-of-it","2. Performance (or the Reputation of It)",[113,914,915],{},"If you hang around tech forums long enough, you'll hear people say Python, and by extension Django is \"slow\". In absolute terms, yes, it's not going to beat a Go or Java or dotnet backend in raw speed. But in practice, I've found Django to be more than fast enough for my projects. That said, for extremely high-performance, low-latency systems, Django might not be the first tool you reach for without careful optimization or caching strategies.",[146,917,922],{"className":918},[919,920,921],"w-full","flex","justify-center",[113,923,924],{},[153,925],{"alt":926,"src":927},"django benchmark fortune","https:\u002F\u002Fres.cloudinary.com\u002Fdhqbr2d4l\u002Fimage\u002Fupload\u002Fv1755144309\u002Fdjango_benchmark_j1gqsh.jpg",[207,929,931],{"id":930},"_3-javascript-framework-integration","3. JavaScript framework integration",[113,933,934],{},"Django works great on the backend, but integrating it smoothly with modern JavaScript frameworks isn't as polished as in some other ecosystems. For example, Laravel has Inertia.js, which makes connecting Vue or React feel easy. With Django, you either stick to traditional server-rendered templates or set up a separate frontend project.",[108,936,938],{"id":937},"final-thoughts","Final Thoughts",[113,940,941],{},"Django has been a big part of my journey as a developer. It's not perfect, but it's powerful. The key is knowing when it's the right tool for the job, and how to make the most of it.",[943,944],"hr",{},[113,946,947],{},[948,949,950],"em",{},"Have you been working with Django too? I'd love to hear about it!",[770,952,953],{},"html pre.shiki code .sRxSC, html code.shiki .sRxSC{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#F92672;--shiki-sepia-font-style:inherit}html pre.shiki code .ss--_, html code.shiki .ss--_{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .swvn1, html code.shiki .swvn1{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .srJo8, html code.shiki .srJo8{--shiki-light:#9C3EDA;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .sD0ED, html code.shiki .sD0ED{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sW6vx, html code.shiki .sW6vx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#24292E;--shiki-default-font-style:inherit;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit;--shiki-sepia:#FD971F;--shiki-sepia-font-style:italic}html pre.shiki code .sGXK2, html code.shiki .sGXK2{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .sAZ-3, html code.shiki .sAZ-3{--shiki-light:#6182B8;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .siCPE, html code.shiki .siCPE{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .squCx, html code.shiki .squCx{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .sQgqH, html code.shiki .sQgqH{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit;--shiki-sepia:#FD971F;--shiki-sepia-font-style:italic}html pre.shiki code .sMTiH, html code.shiki .sMTiH{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sKvfc, html code.shiki .sKvfc{--shiki-light:#E2931D;--shiki-light-text-decoration:inherit;--shiki-default:#6F42C1;--shiki-default-text-decoration:inherit;--shiki-dark:#B392F0;--shiki-dark-text-decoration:inherit;--shiki-sepia:#A6E22E;--shiki-sepia-text-decoration:underline}html pre.shiki code .sW3Pz, html code.shiki .sW3Pz{--shiki-light:#E2931D;--shiki-light-font-style:inherit;--shiki-light-text-decoration:inherit;--shiki-default:#6F42C1;--shiki-default-font-style:inherit;--shiki-default-text-decoration:inherit;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit;--shiki-dark-text-decoration:inherit;--shiki-sepia:#A6E22E;--shiki-sepia-font-style:italic;--shiki-sepia-text-decoration:underline}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .ss7Ak, html code.shiki .ss7Ak{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit;--shiki-sepia:#88846F;--shiki-sepia-font-style:inherit}html pre.shiki code .sMLJd, html code.shiki .sMLJd{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#66D9EF}html pre.shiki code .sDdYn, html code.shiki .sDdYn{--shiki-light:#E53935;--shiki-light-font-style:italic;--shiki-default:#24292E;--shiki-default-font-style:inherit;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit;--shiki-sepia:#FD971F;--shiki-sepia-font-style:italic}html pre.shiki code .sSsL9, html code.shiki .sSsL9{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#FD971F}html pre.shiki code .sYThS, html code.shiki .sYThS{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}",{"title":220,"searchDepth":252,"depth":258,"links":955},[956,957,958,964,969],{"id":110,"depth":252,"text":111},{"id":118,"depth":252,"text":119},{"id":204,"depth":252,"text":205,"children":959},[960,961,962,963],{"id":209,"depth":258,"text":210},{"id":482,"depth":258,"text":483},{"id":847,"depth":258,"text":848},{"id":865,"depth":258,"text":866},{"id":872,"depth":252,"text":873,"children":965},[966,967,968],{"id":876,"depth":258,"text":877},{"id":911,"depth":258,"text":912},{"id":930,"depth":258,"text":931},{"id":937,"depth":252,"text":938},"2025-08-13","After half a decade of building apps with Django, here's my honest take on its strengths, weaknesses, and the lessons I've learned along the way.","md",{"src":156},{"sitemap":975,"schemaOrg":977},{"lastmod":976},"2025-08-20",[978],{"type":979,"headline":980,"author":981,"datePublished":970},"BlogPosting","5 Years with Django: The Good, The Bad, and What I Wish I Knew Earlier",{"type":982,"name":983},"Person","Made Yoga","\u002Fblog\u002F5-years-of-django-pros-and-cons",{"keywords":986,"title":97,"description":971},"django, django review, django pros and cons, python web framework, django developer experience","blog\u002F5-years-of-django-pros-and-cons","kpzi8Cg0jFIzgApPZ4T0B8fQI87FIqkZJeBpkC0GHpY",{"id":990,"title":991,"authors":992,"badge":995,"body":997,"date":1637,"description":1638,"extension":972,"image":1639,"meta":1640,"navigation":50,"path":42,"seo":1645,"stem":1647,"__hash__":1648},"posts\u002Fblog\u002Fai-agent-workflow-deepseek-hermes.md","Experimenting with Hermes Agent + DeepSeek-V4-Flash-0731 for ASP.NET Core and Nuxt",[993],{"name":100,"to":51,"avatar":994},{"src":102},{"label":996},"AI Agents",{"type":105,"value":998,"toc":1623},[999,1013,1028,1031,1034,1038,1052,1063,1069,1072,1075,1079,1083,1091,1095,1111,1119,1123,1126,1142,1146,1153,1165,1173,1176,1397,1400,1404,1411,1414,1418,1451,1500,1515,1522,1525,1529,1540,1598,1601,1605,1611,1617,1620],[146,1000,1002,1003,1008,1009],{"style":1001},"display:flex;align-items:center;justify-content:center;gap:1.5rem;margin:1.5rem 0 2rem;","\n  ",[153,1004],{"src":1005,"alt":1006,"style":1007},"https:\u002F\u002Fres.cloudinary.com\u002Ffpfvgqrg\u002Fimage\u002Fupload\u002Fv1785599903\u002Flogo_w9akfu.png","Hermes Agent","height:4rem;width:auto;max-width:40%;object-fit:contain;","\n  +\n  ",[153,1010],{"src":1011,"alt":1012,"style":1007},"https:\u002F\u002Fres.cloudinary.com\u002Ffpfvgqrg\u002Fimage\u002Fupload\u002Fv1785599605\u002FUk1zNOj4_400x400_xbxycj.jpg","DeepSeek",[113,1014,1015,1016,1019,1020,1023,1024,1027],{},"I've been running ",[1017,1018,1006],"strong",{}," against ",[1017,1021,1022],{},"DeepSeek-V4-Flash-0731"," (API id ",[222,1025,1026],{},"deepseek-v4-flash",") as a cheap loop for ASP.NET Core and Nuxt work. This is a lab note, not a recommendation to abandon whatever you already use.",[113,1029,1030],{},"My frontend teammates lean on Next.js and Claude Code. Fair, that stack pays for itself when the hard part is UI reasoning. Most of my days look different: minimal APIs, EF Core migrations, PostgreSQL, Nuxt pages, tests. Volume and consistency more than deep creative architecture. I've bounced between Codex CLI, and Cursor. Hermes + Flash-0731 is the combination I'm stress-testing right now because the agent loop is cheap enough that I don't flinch at long sessions, and when it stalls, I still hop to a stronger model for a turn.",[113,1032,1033],{},"Flash-0731 is DeepSeek's public-beta Flash checkpoint (re-post-trained for agent work). I'm on it because that's the beta I'm curious about, not because I've crowned a winner.",[108,1035,1037],{"id":1036},"cost-note-why-im-willing-to-experiment","Cost note (why I'm willing to experiment)",[113,1039,1040,1041,1043,1044,1047,1048,1051],{},"Per DeepSeek's API pricing as of this write-up, ",[222,1042,1026],{}," is about ",[1017,1045,1046],{},"$0.14 \u002F $0.28"," per 1M input\u002Foutput tokens (cache hits much lower). In practice my Hermes days land roughly in the ",[1017,1049,1050],{},"pocket-change"," range, far below a Max-style subscription or a heavy Opus API day.",[113,1053,1054,1055,1058,1059,1062],{},"I'm also watching DeepSeek's own agent-harness claims for Flash-0731. On their chart it lands ",[1017,1056,1057],{},"ahead of GLM-5.2"," and ",[1017,1060,1061],{},"close to Claude Opus 4.8"," on several agent-style benches, vendor-reported numbers, not my independent re-run, but enough signal that a cheap Flash tier is worth poking for coding-agent work:",[113,1064,1065],{},[153,1066],{"alt":1067,"src":1068},"DeepSeek-V4-Flash-0731 benchmark chart vs GLM-5.2, Claude Opus 4.8, and other models (DeepSeek harness)","https:\u002F\u002Fres.cloudinary.com\u002Ffpfvgqrg\u002Fimage\u002Fupload\u002Fv1785599423\u002Fdeepseek-v4-flash-0731-benchmark_fddxju.webp",[113,1070,1071],{},"I'm not going to spreadsheet Claude vs Flash here. The interesting part for me is: can a cheap agent, taught my stack, do enough mechanical .NET and Nuxt work that the experiment is worth keeping?",[113,1073,1074],{},"So far: often yes for scaffolding and docs-aware UI. Still fuzzy on gnarly LINQ and auth-sensitive paths.",[108,1076,1078],{"id":1077},"setup-im-running","Setup I'm running",[207,1080,1082],{"id":1081},"install-hermes","Install Hermes",[113,1084,1085,1086],{},"Official docs: ",[124,1087,1090],{"href":1088,"rel":1089},"https:\u002F\u002Fhermes-agent.nousresearch.com\u002Fdocs\u002Fgetting-started\u002Finstallation",[130],"Hermes Agent Installation",[207,1092,1094],{"id":1093},"point-it-at-flash-0731","Point it at Flash-0731",[215,1096,1100],{"className":1097,"code":1098,"language":1099,"meta":220,"style":220},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark monokai","hermes model\n","bash",[222,1101,1102],{"__ignoreMap":220},[225,1103,1104,1108],{"class":227,"line":228},[225,1105,1107],{"class":1106},"sR7ES","hermes",[225,1109,1110],{"class":310}," model\n",[113,1112,1113,1114,1118],{},"Select \u002F configure the DeepSeek provider and use model id ",[1017,1115,1116],{},[222,1117,1026],{}," (serves the V4-Flash-0731 checkpoint on the API).",[108,1120,1122],{"id":1121},"teaching-hermes-the-stack-skills-mcp","Teaching Hermes the stack: skills + MCP",[113,1124,1125],{},"Out of the box, the model doesn't know my folder layout, Nuxt UI v4 quirks, or how I want commits and PRs written. Two layers fix that:",[1127,1128,1129,1136],"ul",{},[1130,1131,1132,1135],"li",{},[1017,1133,1134],{},"Skills",": project conventions (APIs, git\u002FPR style)",[1130,1137,1138,1141],{},[1017,1139,1140],{},"MCP",": live docs and tools (Nuxt\u002FNuxt UI docs, git + GitHub actions)",[207,1143,1145],{"id":1144},"skills-for-net","Skills for .NET",[113,1147,1148,1149,1152],{},"Skills are structured ",[222,1150,1151],{},"SKILL.md"," files (open skill format). Hermes keeps a light index and only pulls full rules when a skill is invoked, which helps with token burn.",[113,1154,1155,1156,1161,1162,240],{},"I start with ",[124,1157,1160],{"href":1158,"rel":1159},"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills",[130],"dotnet\u002Fskills",", then teach project-specific patterns with ",[222,1163,1164],{},"\u002Flearn",[215,1166,1171],{"className":1167,"code":1169,"language":1170},[1168],"language-text","> \u002Flearn the project structure and architectural patterns in .\u002Fsrc\u002Fbackend\u002FMyProject.Api, focus on feature slices and request pipeline\n","text",[222,1172,1169],{"__ignoreMap":220},[113,1174,1175],{},"Example of the kind of skill Hermes distills (trimmed):",[215,1177,1181],{"className":1178,"code":1179,"language":1180,"meta":220,"style":220},"language-markdown shiki shiki-themes material-theme-lighter github-light github-dark monokai","---\nname: aspnetcore-minimal-api\ndescription: Build ASP.NET Core Web APIs with feature-folder modules.\nversion: 0.1.0\nauthor: Hermes\nmetadata:\n  hermes:\n    tags: [AspNetCore, MinimalApi, EfCore, PostgreSQL, ProjectTemplate]\n---\n\n### Feature Module Layout\n\nEach module has three subfolders under a namespace folder:\n\n```\n\u003CModule>\u002F\n  Apis\u002F\u003CFeature>Api.cs\n  Models\u002F\u003CEntity>.cs\n  Services\u002F\u003CFeature>Service.cs\n```\n\n**Minimal API pattern** — static class + extension method on `IEndpointRouteBuilder`:\n\n```csharp\npublic static class SomeFeatureApi\n{\n    public static IEndpointConventionBuilder MapSomeFeatureApi(this IEndpointRouteBuilder endpoints)\n    {\n        var group = endpoints.MapGroup(\"\u002FsomeFeature\").WithTags(\"SomeFeature\");\n\n        group.MapGet(\"\u002F{id}\", GetItem)\n            .WithName(\"GetItem\")\n            .RequireAuthorization(\"SomeFeature.View\");\n\n        return group;\n    }\n\n    private static async Task\u003CResults\u003COk\u003CItemResponse>, NotFound>> GetItem(\n        long id, AppDbContext db) { \u002F* ... *\u002F }\n}\n```\n","markdown",[222,1182,1183,1188,1193,1198,1203,1208,1213,1218,1223,1227,1231,1236,1240,1245,1249,1254,1259,1264,1269,1274,1278,1282,1288,1293,1299,1305,1311,1317,1323,1329,1334,1340,1346,1352,1357,1363,1369,1374,1380,1386,1392],{"__ignoreMap":220},[225,1184,1185],{"class":227,"line":228},[225,1186,1187],{},"---\n",[225,1189,1190],{"class":227,"line":252},[225,1191,1192],{},"name: aspnetcore-minimal-api\n",[225,1194,1195],{"class":227,"line":258},[225,1196,1197],{},"description: Build ASP.NET Core Web APIs with feature-folder modules.\n",[225,1199,1200],{"class":227,"line":285},[225,1201,1202],{},"version: 0.1.0\n",[225,1204,1205],{"class":227,"line":329},[225,1206,1207],{},"author: Hermes\n",[225,1209,1210],{"class":227,"line":380},[225,1211,1212],{},"metadata:\n",[225,1214,1215],{"class":227,"line":385},[225,1216,1217],{},"  hermes:\n",[225,1219,1220],{"class":227,"line":408},[225,1221,1222],{},"    tags: [AspNetCore, MinimalApi, EfCore, PostgreSQL, ProjectTemplate]\n",[225,1224,1225],{"class":227,"line":419},[225,1226,1187],{},[225,1228,1229],{"class":227,"line":443},[225,1230,255],{"emptyLinePlaceholder":50},[225,1232,1233],{"class":227,"line":449},[225,1234,1235],{},"### Feature Module Layout\n",[225,1237,1238],{"class":227,"line":459},[225,1239,255],{"emptyLinePlaceholder":50},[225,1241,1242],{"class":227,"line":477},[225,1243,1244],{},"Each module has three subfolders under a namespace folder:\n",[225,1246,1247],{"class":227,"line":653},[225,1248,255],{"emptyLinePlaceholder":50},[225,1250,1251],{"class":227,"line":683},[225,1252,1253],{},"```\n",[225,1255,1256],{"class":227,"line":688},[225,1257,1258],{},"\u003CModule>\u002F\n",[225,1260,1261],{"class":227,"line":706},[225,1262,1263],{},"  Apis\u002F\u003CFeature>Api.cs\n",[225,1265,1266],{"class":227,"line":734},[225,1267,1268],{},"  Models\u002F\u003CEntity>.cs\n",[225,1270,1271],{"class":227,"line":747},[225,1272,1273],{},"  Services\u002F\u003CFeature>Service.cs\n",[225,1275,1276],{"class":227,"line":805},[225,1277,1253],{},[225,1279,1280],{"class":227,"line":810},[225,1281,255],{"emptyLinePlaceholder":50},[225,1283,1285],{"class":227,"line":1284},22,[225,1286,1287],{},"**Minimal API pattern** — static class + extension method on `IEndpointRouteBuilder`:\n",[225,1289,1291],{"class":227,"line":1290},23,[225,1292,255],{"emptyLinePlaceholder":50},[225,1294,1296],{"class":227,"line":1295},24,[225,1297,1298],{},"```csharp\n",[225,1300,1302],{"class":227,"line":1301},25,[225,1303,1304],{},"public static class SomeFeatureApi\n",[225,1306,1308],{"class":227,"line":1307},26,[225,1309,1310],{},"{\n",[225,1312,1314],{"class":227,"line":1313},27,[225,1315,1316],{},"    public static IEndpointConventionBuilder MapSomeFeatureApi(this IEndpointRouteBuilder endpoints)\n",[225,1318,1320],{"class":227,"line":1319},28,[225,1321,1322],{},"    {\n",[225,1324,1326],{"class":227,"line":1325},29,[225,1327,1328],{},"        var group = endpoints.MapGroup(\"\u002FsomeFeature\").WithTags(\"SomeFeature\");\n",[225,1330,1332],{"class":227,"line":1331},30,[225,1333,255],{"emptyLinePlaceholder":50},[225,1335,1337],{"class":227,"line":1336},31,[225,1338,1339],{},"        group.MapGet(\"\u002F{id}\", GetItem)\n",[225,1341,1343],{"class":227,"line":1342},32,[225,1344,1345],{},"            .WithName(\"GetItem\")\n",[225,1347,1349],{"class":227,"line":1348},33,[225,1350,1351],{},"            .RequireAuthorization(\"SomeFeature.View\");\n",[225,1353,1355],{"class":227,"line":1354},34,[225,1356,255],{"emptyLinePlaceholder":50},[225,1358,1360],{"class":227,"line":1359},35,[225,1361,1362],{},"        return group;\n",[225,1364,1366],{"class":227,"line":1365},36,[225,1367,1368],{},"    }\n",[225,1370,1372],{"class":227,"line":1371},37,[225,1373,255],{"emptyLinePlaceholder":50},[225,1375,1377],{"class":227,"line":1376},38,[225,1378,1379],{},"    private static async Task\u003CResults\u003COk\u003CItemResponse>, NotFound>> GetItem(\n",[225,1381,1383],{"class":227,"line":1382},39,[225,1384,1385],{},"        long id, AppDbContext db) { \u002F* ... *\u002F }\n",[225,1387,1389],{"class":227,"line":1388},40,[225,1390,1391],{},"}\n",[225,1393,1395],{"class":227,"line":1394},41,[225,1396,1253],{},[113,1398,1399],{},"After that, prompts like \"add a feature slice for invoices\" land closer to the house style instead of generic controller soup.",[207,1401,1403],{"id":1402},"skills-for-git-prs","Skills for git \u002F PRs",[113,1405,1406,1407,1410],{},"I want the agent to ship the boring git loop without inventing commit noise. A git skill covers house rules: short why-focused commit messages, ",[222,1408,1409],{},"Co-authored-by"," lines when Hermes wrote most of the diff, PR title\u002Fbody shape (summary + test plan), no force-push to main, don't commit secrets.",[113,1412,1413],{},"That way \"commit this and open a PR\" produces something I'd actually submit, not a wall of AI filler.",[207,1415,1417],{"id":1416},"nuxt-nuxt-ui-mcps-live-docs","Nuxt + Nuxt UI MCPs (live docs)",[113,1419,1420,1421,1424,1425,1428,1429,1432,1433,1436,1437,1440,1441,1444,1445,1450],{},"Skills teach ",[948,1422,1423],{},"my"," conventions. MCP teaches ",[948,1426,1427],{},"current"," framework docs. Hermes needs ",[222,1430,1431],{},"--url",", ",[222,1434,1435],{},"--command",", or ",[222,1438,1439],{},"--preset"," on ",[222,1442,1443],{},"mcp add"," (",[124,1446,1449],{"href":1447,"rel":1448},"https:\u002F\u002Fhermes-agent.nousresearch.com\u002Fdocs\u002Fguides\u002Fuse-mcp-with-hermes",[130],"docs","). For the hosted Nuxt docs servers:",[215,1452,1454],{"className":1097,"code":1453,"language":1099,"meta":220,"style":220},"hermes mcp add nuxt --url \"https:\u002F\u002Fnuxt.com\u002Fmcp\"\nhermes mcp add nuxtui --url \"https:\u002F\u002Fui.nuxt.com\u002Fmcp\"\n",[222,1455,1456,1480],{"__ignoreMap":220},[225,1457,1458,1460,1463,1466,1469,1473,1475,1478],{"class":227,"line":228},[225,1459,1107],{"class":1106},[225,1461,1462],{"class":310}," mcp",[225,1464,1465],{"class":310}," add",[225,1467,1468],{"class":310}," nuxt",[225,1470,1472],{"class":1471},"sFhLe"," --url",[225,1474,608],{"class":306},[225,1476,1477],{"class":310},"https:\u002F\u002Fnuxt.com\u002Fmcp",[225,1479,614],{"class":306},[225,1481,1482,1484,1486,1488,1491,1493,1495,1498],{"class":227,"line":252},[225,1483,1107],{"class":1106},[225,1485,1462],{"class":310},[225,1487,1465],{"class":310},[225,1489,1490],{"class":310}," nuxtui",[225,1492,1472],{"class":1471},[225,1494,608],{"class":306},[225,1496,1497],{"class":310},"https:\u002F\u002Fui.nuxt.com\u002Fmcp",[225,1499,614],{"class":306},[113,1501,1502,1503,1506,1507,1510,1511,1514],{},"Then ",[222,1504,1505],{},"hermes mcp test nuxt"," \u002F ",[222,1508,1509],{},"hermes mcp test nuxtui"," (or ",[222,1512,1513],{},"\u002Freload-mcp"," in a session).",[113,1516,1517,1518,1521],{},"With those connected, asking \"how do I use ",[222,1519,1520],{},"UBadge"," with an icon in Nuxt UI v4?\" can pull real component metadata instead of a confident wrong API. Same for Nuxt routing, content, and module docs.",[113,1523,1524],{},"Day-to-day difference I've noticed: without MCP, Flash will happily invent prop names. With MCP, the UI glue is boring in a good way, which is what I want from a cheap agent.",[207,1526,1528],{"id":1527},"git-github-mcps-stage-commit-push-pr","Git + GitHub MCPs (stage → commit → push → PR)",[113,1530,1531,1532,1535,1536,1539],{},"Docs MCP is only half the loop. I also connect git and GitHub MCPs so Hermes can actually move the work. Local git via ",[222,1533,1534],{},"uvx",", GitHub via the official stdio server (set ",[222,1537,1538],{},"GITHUB_PERSONAL_ACCESS_TOKEN"," in the server env \u002F Hermes config):",[215,1541,1543],{"className":1097,"code":1542,"language":1099,"meta":220,"style":220},"hermes mcp add git --command uvx --args mcp-server-git --repository \u002Fabsolute\u002Fpath\u002Fto\u002Frepo\nhermes mcp add github --command npx --args -y @modelcontextprotocol\u002Fserver-github\n",[222,1544,1545,1574],{"__ignoreMap":220},[225,1546,1547,1549,1551,1553,1556,1559,1562,1565,1568,1571],{"class":227,"line":228},[225,1548,1107],{"class":1106},[225,1550,1462],{"class":310},[225,1552,1465],{"class":310},[225,1554,1555],{"class":310}," git",[225,1557,1558],{"class":1471}," --command",[225,1560,1561],{"class":310}," uvx",[225,1563,1564],{"class":1471}," --args",[225,1566,1567],{"class":310}," mcp-server-git",[225,1569,1570],{"class":1471}," --repository",[225,1572,1573],{"class":310}," \u002Fabsolute\u002Fpath\u002Fto\u002Frepo\n",[225,1575,1576,1578,1580,1582,1585,1587,1590,1592,1595],{"class":227,"line":252},[225,1577,1107],{"class":1106},[225,1579,1462],{"class":310},[225,1581,1465],{"class":310},[225,1583,1584],{"class":310}," github",[225,1586,1558],{"class":1471},[225,1588,1589],{"class":310}," npx",[225,1591,1564],{"class":1471},[225,1593,1594],{"class":1471}," -y",[225,1596,1597],{"class":310}," @modelcontextprotocol\u002Fserver-github\n",[113,1599,1600],{},"With those plus the git skill, a typical close-out looks like: stage the right files → commit with a sane message (and co-author trailer when appropriate) → push the branch → open a PR with a usable description. I'm still babysitting auth and anything destructive, but the mechanical GitHub dance is what I'm trying to automate.",[108,1602,1604],{"id":1603},"whats-next-in-the-experiment","What's next in the experiment",[113,1606,1607,1608,1610],{},"Working well enough to keep: Hermes + ",[222,1609,1026],{},", dotnet + Nuxt + git skills, Nuxt\u002FNuxt UI MCP for component truth, git\u002FGitHub MCP for the commit→PR path.",[113,1612,1613,1614,1616],{},"Still fuzzy: how far I can push Flash-0731 before I should route hard turns automatically; how much skill surface area is worth maintaining by hand vs regenerating with ",[222,1615,1164],{},"; how much of the GitHub loop I trust without a human glance.",[113,1618,1619],{},"If the beta shifts or Pro's official drop lands, I'll note what changes. For now this is the setup on my machine, cheap, opinionated, and unfinished on purpose.",[770,1621,1622],{},"html pre.shiki code .sR7ES, html code.shiki .sR7ES{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .sFhLe, html code.shiki .sFhLe{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .siCPE, html code.shiki .siCPE{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}",{"title":220,"searchDepth":252,"depth":258,"links":1624},[1625,1626,1630,1636],{"id":1036,"depth":252,"text":1037},{"id":1077,"depth":252,"text":1078,"children":1627},[1628,1629],{"id":1081,"depth":258,"text":1082},{"id":1093,"depth":258,"text":1094},{"id":1121,"depth":252,"text":1122,"children":1631},[1632,1633,1634,1635],{"id":1144,"depth":258,"text":1145},{"id":1402,"depth":258,"text":1403},{"id":1416,"depth":258,"text":1417},{"id":1527,"depth":258,"text":1528},{"id":1603,"depth":252,"text":1604},"2026-08-01","Lab notes on running Hermes Agent with DeepSeek-V4-Flash-0731 beta, teaching .NET and Nuxt via skills, wiring Nuxt and Nuxt UI MCPs, and what still feels rough.",{"src":1005},{"sitemap":1641,"schemaOrg":1642},{"lastmod":1637},[1643],{"type":979,"headline":991,"author":1644,"datePublished":1637},{"type":982,"name":983},{"keywords":1646,"title":991,"description":1638},"Hermes agent, DeepSeek-V4-Flash-0731, deepseek-v4-flash, AI coding agent, .NET, Nuxt, Nuxt UI, MCP server, skills","blog\u002Fai-agent-workflow-deepseek-hermes","ttAsL3QGrYyUEZEf-HsEnYxXL8f0z54aELrq8a8bNos",{"id":1650,"title":1651,"authors":1652,"badge":1655,"body":1657,"date":1637,"description":1921,"extension":972,"image":1922,"meta":1923,"navigation":50,"path":1928,"seo":1929,"stem":1931,"__hash__":1932},"posts\u002Fblog\u002Fauthendpoints-3-0-rc.md","AuthEndpoints 3.0 RC: a composable auth endpoints library for ASP.NET Core",[1653],{"name":100,"to":51,"avatar":1654},{"src":102},{"label":1656},"Open Source",{"type":105,"value":1658,"toc":1911},[1659,1662,1665,1669,1672,1676,1679,1683,1686,1690,1693,1769,1772,1776,1804,1808,1817,1820,1831,1834,1838,1862,1865,1908],[113,1660,1661],{},"Today I'm releasing AuthEndpoints 3.0 RC: an auth library for ASP.NET Core that turns auth setup from a project phase into a setup step.",[113,1663,1664],{},"If you build ASP.NET Core backends or web APIs, you may have written this before. Register, login, email confirmation, password reset, 2FA, session management. Same code in every project, different user model each time. AuthEndpoints packages that work into a library on top of ASP.NET Core Identity, so a secure auth layer takes minutes to stand up instead of a week of copy-paste.",[108,1666,1668],{"id":1667},"why-its-good-for-developer-productivity","Why it's good for developer productivity",[113,1670,1671],{},"Two design decisions drive most of the value.",[207,1673,1675],{"id":1674},"opinionated-options","Opinionated options.",[113,1677,1678],{},"Auth comes with a lot of decisions, and most of them have one right answer for a web frontend backed by a single API. AuthEndpoints bakes those in: rate limiting, antiforgery, lockout-aware login, and hashed refresh tokens with reuse detection are on by default. The hardened path is the default path, so you don't have to know the pitfalls to avoid them.",[207,1680,1682],{"id":1681},"composable-endpoints","Composable endpoints.",[113,1684,1685],{},"AuthEndpoints is organized as endpoints and modules you can compose manually. Need email\u002Fpassword with JWT? Cookie sessions with passkeys? 2FA on top of that? You pick the pieces, and the routes and validation stay consistent across the whole setup.",[108,1687,1689],{"id":1688},"the-quick-start","The quick start",[113,1691,1692],{},"Three extension methods and a few lines:",[215,1694,1698],{"className":1695,"code":1696,"language":1697,"meta":220,"style":220},"language-cs shiki shiki-themes material-theme-lighter github-light github-dark monokai","builder.Services.AddDbContext\u003CAppDbContext>(\u002F* your provider *\u002F);\n\nbuilder.Services.AddAuthEndpoints\u003CAppUser, AppDbContext>(o =>\n{\n    o.Passkeys.ServerDomain = \"example.com\"; \u002F\u002F required in Production\n});\n\nbuilder.Services.AddTransient\u003CIEmailSender\u003CAppUser>, MyEmailSender>();\n\nvar app = builder.Build();\n\napp.UseAuthEndpoints();\napp.MapAuthEndpoints\u003CAppUser>();\n\napp.Run();\n","cs",[222,1699,1700,1705,1709,1714,1718,1723,1728,1732,1737,1741,1746,1750,1755,1760,1764],{"__ignoreMap":220},[225,1701,1702],{"class":227,"line":228},[225,1703,1704],{},"builder.Services.AddDbContext\u003CAppDbContext>(\u002F* your provider *\u002F);\n",[225,1706,1707],{"class":227,"line":252},[225,1708,255],{"emptyLinePlaceholder":50},[225,1710,1711],{"class":227,"line":258},[225,1712,1713],{},"builder.Services.AddAuthEndpoints\u003CAppUser, AppDbContext>(o =>\n",[225,1715,1716],{"class":227,"line":285},[225,1717,1310],{},[225,1719,1720],{"class":227,"line":329},[225,1721,1722],{},"    o.Passkeys.ServerDomain = \"example.com\"; \u002F\u002F required in Production\n",[225,1724,1725],{"class":227,"line":380},[225,1726,1727],{},"});\n",[225,1729,1730],{"class":227,"line":385},[225,1731,255],{"emptyLinePlaceholder":50},[225,1733,1734],{"class":227,"line":408},[225,1735,1736],{},"builder.Services.AddTransient\u003CIEmailSender\u003CAppUser>, MyEmailSender>();\n",[225,1738,1739],{"class":227,"line":419},[225,1740,255],{"emptyLinePlaceholder":50},[225,1742,1743],{"class":227,"line":443},[225,1744,1745],{},"var app = builder.Build();\n",[225,1747,1748],{"class":227,"line":449},[225,1749,255],{"emptyLinePlaceholder":50},[225,1751,1752],{"class":227,"line":459},[225,1753,1754],{},"app.UseAuthEndpoints();\n",[225,1756,1757],{"class":227,"line":477},[225,1758,1759],{},"app.MapAuthEndpoints\u003CAppUser>();\n",[225,1761,1762],{"class":227,"line":653},[225,1763,255],{"emptyLinePlaceholder":50},[225,1765,1766],{"class":227,"line":683},[225,1767,1768],{},"app.Run();\n",[113,1770,1771],{},"That maps the whole account lifecycle: register, confirm email, forgot and reset password, manage info and 2FA, plus step-up re-authentication for sensitive actions. You bring the DbContext and an email sender. The library handles the rest, including your choice of cookie sessions, Identity bearer tokens, or Simple JWT, and passkeys (WebAuthn) for passwordless sign-in.",[108,1773,1775],{"id":1774},"whats-in-30","What's in 3.0",[1127,1777,1778,1784,1790,1795],{},[1130,1779,1780,1783],{},[1017,1781,1782],{},"Sign-in stacks you pick",": cookie sessions, Identity bearer tokens, or Simple JWT. The endpoints stay the same; the token strategy is configuration.",[1130,1785,1786,1789],{},[1017,1787,1788],{},"Passkeys (WebAuthn)"," for passwordless register and login, working alongside email\u002Fpassword rather than replacing it.",[1130,1791,1792,1794],{},[1017,1793,80],{},": the opinionated defaults, enabled without extra setup.",[1130,1796,1797,1800,1801,240],{},[1017,1798,1799],{},"GitHub and Google OAuth"," through an optional separate package, ",[222,1802,1803],{},"AuthEndpoints.External.OAuth",[108,1805,1807],{"id":1806},"help-shape-the-final-api","Help shape the final API",[113,1809,1810,1811,1816],{},"3.0 is a rewrite, and the API isn't frozen yet. An RC is the last moment to change things cheaply; once 3.0 ships stable, breaking changes cost everyone who adopted it. If you try it and something feels off, please ",[124,1812,1815],{"href":1813,"rel":1814},"https:\u002F\u002Fgithub.com\u002Fmadeyoga\u002FAuthEndpoints\u002Fissues",[130],"open an issue",". Your feedback decides what the API looks like when it ships.",[113,1818,1819],{},"In particular, I'd love to hear:",[1127,1821,1822,1825,1828],{},[1130,1823,1824],{},"Do naming or composition feel awkward for your app?",[1130,1826,1827],{},"Are the defaults too strict or too loose?",[1130,1829,1830],{},"Is a module missing that you'd need in a real project?",[113,1832,1833],{},"Mention which stack you used (cookies, JWT, passkeys) and what you were trying to do. No template required.",[108,1835,1837],{"id":1836},"try-it","Try it",[215,1839,1841],{"className":1097,"code":1840,"language":1099,"meta":220,"style":220},"dotnet add package AuthEndpoints --version 3.0.0-rc.3\n",[222,1842,1843],{"__ignoreMap":220},[225,1844,1845,1848,1850,1853,1856,1859],{"class":227,"line":228},[225,1846,1847],{"class":1106},"dotnet",[225,1849,1465],{"class":310},[225,1851,1852],{"class":310}," package",[225,1854,1855],{"class":310}," AuthEndpoints",[225,1857,1858],{"class":1471}," --version",[225,1860,1861],{"class":310}," 3.0.0-rc.3\n",[113,1863,1864],{},"Install the package, or open the demo and click through the flows. If something feels awkward, breaks, or is missing, open an issue, since that's how 3.0 stable gets shaped.",[1127,1866,1867,1879,1889,1899],{},[1130,1868,1869,1872,1873,1878],{},[1017,1870,1871],{},"Demo app",": ",[124,1874,1877],{"href":1875,"rel":1876},"https:\u002F\u002Fgithub.com\u002Fmadeyoga\u002FAuthEndpointsDemo",[130],"madeyoga\u002FAuthEndpointsDemo",", an ASP.NET Core API plus a Nuxt 4 \u002F Nuxt UI playground, so you can click through the flows without writing a frontend first.",[1130,1880,1881,1884,1885,240],{},[1017,1882,1883],{},"Feedback",": open an issue on ",[124,1886,1888],{"href":1813,"rel":1887},[130],"madeyoga\u002FAuthEndpoints",[1130,1890,1891,1872,1894,1898],{},[1017,1892,1893],{},"Docs",[124,1895,1897],{"href":58,"rel":1896},[130],"madeyoga.github.io\u002FAuthEndpoints"," with configuration, composable modules, route tables, and production guidance.",[1130,1900,1901,1872,1904,1907],{},[1017,1902,1903],{},"Repository",[124,1905,55],{"href":59,"rel":1906},[130]," (MIT).",[770,1909,1910],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .sR7ES, html code.shiki .sR7ES{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .sFhLe, html code.shiki .sFhLe{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}",{"title":220,"searchDepth":252,"depth":258,"links":1912},[1913,1917,1918,1919,1920],{"id":1667,"depth":252,"text":1668,"children":1914},[1915,1916],{"id":1674,"depth":258,"text":1675},{"id":1681,"depth":258,"text":1682},{"id":1688,"depth":252,"text":1689},{"id":1774,"depth":252,"text":1775},{"id":1806,"depth":252,"text":1807},{"id":1836,"depth":252,"text":1837},"Announcing AuthEndpoints 3.0 RC, an auth library for ASP.NET Core. Composable auth endpoints on top of ASP.NET Core Identity: registration, login, 2FA, password reset, and passkeys bootstrapped in minutes.",{"src":60},{"sitemap":1924,"schemaOrg":1925},{"lastmod":1637},[1926],{"type":979,"headline":1651,"author":1927,"datePublished":1637},{"type":982,"name":983},"\u002Fblog\u002Fauthendpoints-3-0-rc",{"keywords":1930,"title":1651,"description":1921},"AuthEndpoints, ASP.NET Core authentication, .NET 10, passkeys, WebAuthn, JWT, ASP.NET Core Identity, NuGet","blog\u002Fauthendpoints-3-0-rc","eRPoXxePrED2vybU0Ifjd5Q6ue0RoG_LLSYhw_0SfoU",{"id":1934,"title":1935,"authors":1936,"badge":1939,"body":1940,"date":49,"description":2491,"extension":972,"image":2492,"meta":2494,"navigation":50,"path":38,"seo":2499,"stem":2501,"__hash__":2502},"posts\u002Fblog\u002Fhermes-bot-mode.md","Hermes Agent Bot Mode: how I split work across three specialist bots",[1937],{"name":100,"to":51,"avatar":1938},{"src":102},{"label":996},{"type":105,"value":1941,"toc":2473},[1942,1946,1949,1959,1977,1981,1988,2006,2013,2016,2032,2039,2051,2054,2058,2066,2072,2083,2086,2090,2097,2100,2103,2106,2114,2117,2124,2130,2133,2136,2148,2151,2162,2169,2172,2175,2204,2207,2210,2223,2227,2233,2248,2255,2300,2310,2313,2330,2333,2348,2371,2375,2386,2389,2395,2398,2404,2407,2414,2418,2422,2425,2429,2432,2436,2445,2449,2452,2456,2459,2470],[146,1943,1002,1944],{"style":1001},[153,1945],{"src":1005,"alt":1006,"style":1007},[113,1947,1948],{},"I used to keep one Hermes profile for everything: blog drafts, Nuxt pages, ASP.NET APIs. Same memory, same skill dump, same MCP list. The chat got noisy, and the agent kept reaching for the wrong conventions.",[113,1950,1951,1955,1956,240],{},[124,1952,35],{"href":1953,"rel":1954},"https:\u002F\u002Fhermes-agent.nousresearch.com\u002Fdocs\u002Fuser-guide\u002Fbot-mode",[130]," is how I split that into named teammates. The docs put it in one line: Bot Mode turns your Hermes profiles into a roster of named Bots. Each Bot is still a profile. It shows up with a role and a face, plus a canonical Bot Chat that stays the relationship instead of forking into a scratch session every time you type ",[222,1957,1958],{},"\u002Fnew",[113,1960,1961,1962,1965,1966,1969,1970,1973,1974,240],{},"I now run ",[1017,1963,1964],{},"Blogi"," for writing, ",[1017,1967,1968],{},"Nuxti"," for Nuxt UI, and ",[1017,1971,1972],{},"Aspi"," for ASP.NET. This is the setup, the messaging flow, and the parts that still annoy me. If you want the earlier single-agent loop (skills, MCP, Flash-0731), that's in my ",[124,1975,1976],{"href":42},"Hermes + DeepSeek lab note",[108,1978,1980],{"id":1979},"what-bot-mode-is","What Bot Mode is",[113,1982,1983,1984,1987],{},"A Bot is a Hermes profile. Isolated config, memory, skills, credentials, and chat history live under ",[222,1985,1986],{},"~\u002F.hermes\u002Fprofiles\u002F\u003Cname>\u002F",". Bot Mode is a UI over that primitive. Chat with the same agent from the desktop roster or from a shell:",[215,1989,1991],{"className":1097,"code":1990,"language":1099,"meta":220,"style":220},"hermes -p blogi chat\n",[222,1992,1993],{"__ignoreMap":220},[225,1994,1995,1997,2000,2003],{"class":227,"line":228},[225,1996,1107],{"class":1106},[225,1998,1999],{"class":1471}," -p",[225,2001,2002],{"class":310}," blogi",[225,2004,2005],{"class":310}," chat\n",[113,2007,2008,2009,2012],{},"Routines on a Bot are ordinary Hermes cron jobs. They show up in ",[222,2010,2011],{},"hermes cron list",". Nothing extra is stored, and there's no background daemon that only Bot Mode understands.",[113,2014,2015],{},"On the desktop it appears as a Bots tab next to Sessions. The roster is one row per profile: avatar, latest-message preview, timestamp. Click a Bot and you land in its canonical Bot Chat, created and pinned the moment the Bot exists. Sessions still exist (the context menu filters the last 200 stored conversations on that profile). The difference is the click-to-chat path always returns to the same forever chat.",[113,2017,2018,2019,2021,2022,2025,2026,2029,2030,240],{},"That forever chat is the part I care about. Typing ",[222,2020,1958],{}," or ",[222,2023,2024],{},"\u002Freset"," inside the canonical Bot Chat would fork the relationship. The composer reroutes those to ",[222,2027,2028],{},"\u002Fcompact"," instead: fresh working context, same conversation. Regular sessions on the same profile still get a real ",[222,2031,1958],{},[113,2033,2034,2035,2038],{},"You can pin a model per Bot, write a custom ",[222,2036,2037],{},"SOUL.md",", and tick skills, toolsets, and MCP servers so a specialist only loads what it needs. Shared keys are the default, so refreshing a token on one Bot doesn't invalidate the others. Older gateways copy credentials instead; that still works, it's just forked.",[113,2040,2041,2042,2046,2047,2050],{},"The words I use come from the ",[124,2043,2045],{"href":1953,"rel":2044},[130],"official Bot Mode page",": Bot, profile, teammate, roster, Bot Chat, handoff, group chat. \"Handoff\" here means an ",[222,2048,2049],{},"@mention"," or a CLI message into another Bot's Bot Chat, not a workflow engine.",[113,2052,2053],{},"Bot Mode ships built into the desktop app and is on by default. No plugin install. Flip it off in Settings → Plugins → Bots if you want the old session list back. Profiles, sessions, and cron jobs stay put either way. Bot Mode never owns the data; it only renders it.",[108,2055,2057],{"id":2056},"why-i-split-the-work","Why I split the work",[113,2059,2060,2061,2065],{},"I'm a ",[124,2062,2064],{"href":2063},"\u002Fabout","fullstack .NET and Nuxt developer",". Most weeks that's minimal APIs, EF Core, PostgreSQL, Nuxt pages, and the occasional blog post about the same stack. One profile can do all of that. It just does it with a bloated prompt.",[113,2067,2068,2069,2071],{},"Skills in Hermes are ",[222,2070,1151],{}," files. The agent keeps a light index and pulls full rules when a skill is invoked, which helps with token burn. Even so, a profile that holds writing skills, Nuxt UI skills, and ASP.NET skills will grab the wrong house style. Coding turns start sounding like blog intros, and writing turns invent Nuxt prop names.",[113,2073,2074,2075,2078,2079,2082],{},"Splitting by domain is the boring fix. Blogi never sees ",[222,2076,2077],{},"aspnetcore-minimal-api",". Aspi never loads ",[222,2080,2081],{},"humanizer",". Nuxti can hammer Nuxt UI MCP without also carrying Prima accounting rules.",[113,2084,2085],{},"That's how my week actually splits. If I added a Unity-heavy stretch I might give that its own Bot. I didn't, yet. Aspi already has the Unity MCP listed, which is leftover surface I should probably turn off.",[108,2087,2089],{"id":2088},"the-bots","The bots",[146,2091,1002,2092],{"style":1001},[153,2093],{"src":2094,"alt":2095,"style":2096},"https:\u002F\u002Fres.cloudinary.com\u002Ffpfvgqrg\u002Fimage\u002Fupload\u002Fv1787128571\u002FHermes_2026-08-19_16-33-04_nk7jrp.jpg","Hermes Agent Bot mode","height:24rem;width:auto;max-width:40%;object-fit:contain;",[113,2098,2099],{},"Each one is a named profile with a tight skill list and the MCPs that profile actually uses. I created them from the New Agent dialog (name, title, description) and then trimmed capabilities in Edit Profile.",[207,2101,1964],{"id":2102},"blogi",[113,2104,2105],{},"Content writer. That's the profile I use for posts like this.",[113,2107,2108,2109,1432,2112,240],{},"Skills: ",[222,2110,2111],{},"blog-seo-writer",[222,2113,2081],{},[113,2115,2116],{},"MCPs: Nuxt, GitHub (HTTP), Nuxt UI, X search.",[113,2118,2119,2120,2123],{},"The Nuxt and Nuxt UI MCPs look odd on a writer until you remember the blog is a Nuxt Content site. Blogi needs to know how posts are shaped (YAML frontmatter, ",[222,2121,2122],{},"content\u002Fblog\u002F\u003Cslug>.md",", the same author block as the other entries) without also knowing how I map a minimal API. GitHub is there so it can open a PR when I ask. X search is optional; I rarely need it for a lab note.",[113,2125,2126,2127,2129],{},"I keep Blogi's ",[222,2128,2037],{}," short: first person, no em dashes, no \"robust \u002F seamless \u002F showcase\", match the existing posts. The humanizer skill is the checklist. The SEO skill is the structure (one primary keyword, meta around 155 characters, keyword in the first 100 words). Neither skill should leak into Aspi's commit messages.",[207,2131,1968],{"id":2132},"nuxti",[113,2134,2135],{},"Nuxt UI engineer. Nuxt 3\u002F4, Nuxt UI 4, Nuxt Content 3, Tailwind.",[113,2137,2108,2138,1432,2141,1432,2144,2147],{},[222,2139,2140],{},"nuxt-development",[222,2142,2143],{},"nuxt-ui",[222,2145,2146],{},"hermes-agent",", plus the shared software-dev skills I keep on coding profiles (git\u002FPR habits, the usual debugging loop).",[113,2149,2150],{},"MCPs: Nuxt, nuxtui, github-http, mcp-server-git.",[113,2152,2153,2154,2157,2158,2161],{},"This is the bot I want in the repo when the task is a page, a ",[222,2155,2156],{},"UButton"," variant, or a content collection quirk. Live docs MCP is the same trick I wrote about in the ",[124,2159,2160],{"href":42},"DeepSeek lab note",": without it, a cheap model invents prop names; with it, the UI glue stays boring.",[113,2163,2164,2165,2168],{},"Nuxti is allowed to touch ",[222,2166,2167],{},"app\u002F"," and the Vue files. I still don't want it \"fixing\" an EF Core migration because it noticed a YAML typo and kept going.",[207,2170,1972],{"id":2171},"aspi",[113,2173,2174],{},"Backend bot. ASP.NET Core Web APIs, EF Core, PostgreSQL.",[113,2176,2108,2177,1432,2179,1432,2182,1432,2185,1432,2188,1432,2191,1432,2194,1432,2197,2200,2201,2203],{},[222,2178,2077],{},[222,2180,2181],{},"dotnet-ecosystem",[222,2183,2184],{},"farmora-backend",[222,2186,2187],{},"farmora-accounting",[222,2189,2190],{},"commit-changes",[222,2192,2193],{},"systematic-debugging",[222,2195,2196],{},"requesting-code-review",[222,2198,2199],{},"plan",", plus ",[222,2202,2146],{}," and the github-* skills.",[113,2205,2206],{},"MCPs: Nuxt, nuxtui, mcp-server-git, github-http.",[113,2208,2209],{},"The Nuxt MCPs on a backend bot are the messy part. Some weeks Aspi has to read a frontend contract. Most weeks they're noise. Unity is sitting there for a different experiment. I haven't cleaned that list yet, which is a good example of Bot Mode not magically enforcing discipline. You still have to tick the boxes.",[113,2211,2212,2213,2216,2217,2219,2220,240],{},"Aspi is the profile I'd hand ",[124,2214,55],{"href":2215},"\u002Fprojects\u002Fauthendpoints"," work, or a feature slice on a client API. The ",[222,2218,2077],{}," skill is the same house layout I published in the earlier lab note: feature folders, static Map* extension methods, no controller soup. When the task is \"announce a release,\" I don't use Aspi. That's Blogi's job, as in the ",[124,2221,2222],{"href":1928},"AuthEndpoints 3.0 RC post",[108,2224,2226],{"id":2225},"how-they-message-each-other","How they message each other",[113,2228,2229,2230,2232],{},"Two paths matter for me: ",[222,2231,2049],{}," from a chat I'm already in, and a headless CLI drop into a teammate's Bot Chat.",[113,2234,2235,2236,2239,2240,2243,2244,2247],{},"In any chat, ",[222,2237,2238],{},"@aspi have a look at this"," makes the active Bot hand the message off, wait for a reply, and report back. Mention names are checked against the live roster, so an email address or an unknown ",[222,2241,2242],{},"@"," is left alone. If the teammate lives on another registered connection, you use ",[222,2245,2246],{},"@name-device"," when names collide. I run everything on one machine, so I haven't needed that yet.",[113,2249,2250,2251,2254],{},"Direct messages are the same CLI you'd run yourself. The Bot writes the body to a temp file (so quotes, ",[222,2252,2253],{},"$(...)",", and backticks aren't shell-interpreted), then:",[215,2256,2258],{"className":1097,"code":2257,"language":1099,"meta":220,"style":220},"hermes -p nuxti chat --in ~ -c \"Bot Chat\" --create-if-missing -Q --query-file \u002Ftmp\u002Fmsg.txt\n",[222,2259,2260],{"__ignoreMap":220},[225,2261,2262,2264,2266,2269,2272,2275,2278,2281,2283,2286,2288,2291,2294,2297],{"class":227,"line":228},[225,2263,1107],{"class":1106},[225,2265,1999],{"class":1471},[225,2267,2268],{"class":310}," nuxti",[225,2270,2271],{"class":310}," chat",[225,2273,2274],{"class":1471}," --in",[225,2276,2277],{"class":310}," ~",[225,2279,2280],{"class":1471}," -c",[225,2282,608],{"class":306},[225,2284,2285],{"class":310},"Bot Chat",[225,2287,799],{"class":306},[225,2289,2290],{"class":1471}," --create-if-missing",[225,2292,2293],{"class":1471}," -Q",[225,2295,2296],{"class":1471}," --query-file",[225,2298,2299],{"class":310}," \u002Ftmp\u002Fmsg.txt\n",[113,2301,2302,2303,2306,2307,2309],{},"The file starts with an attribution prefix like ",[222,2304,2305],{},"Message from 🤖 blogi (@blogi):",". The receiving Bot sees it the next time it runs. The messaging protocol is injected into the canonical Bot Chat system prompt at prompt-build time, including when a teammate opens that chat headlessly. Regular sessions and ",[222,2308,2037],{}," stay untouched.",[113,2311,2312],{},"That's a config flag, on by default:",[215,2314,2318],{"className":2315,"code":2316,"language":2317,"meta":220,"style":220},"language-yaml shiki shiki-themes material-theme-lighter github-light github-dark monokai","agent:\n  bot_mode_protocol: true\n","yaml",[222,2319,2320,2325],{"__ignoreMap":220},[225,2321,2322],{"class":227,"line":228},[225,2323,2324],{},"agent:\n",[225,2326,2327],{"class":227,"line":252},[225,2328,2329],{},"  bot_mode_protocol: true\n",[113,2331,2332],{},"Delivery is per-invocation. If Nuxti is mid-turn, Blogi's message waits. Live interrupt of a Bot that's already talking is listed as future work in the docs. In practice I don't fire a handoff and walk away. I check the other Bot Chat.",[113,2334,2335,2336,2339,2340,2343,2344,2347],{},"Group chats exist too: 2 to 6 Bots, Open chat on a group row, up to three serial rounds, 10 messages per send. ",[222,2337,2338],{},"@name"," pulls a quiet member in. ",[222,2341,2342],{},"@user"," pings you, and the group row gets a needs-you badge. Each member keeps its own ",[222,2345,2346],{},"Group: \u003Cname>"," session. I haven't made Blogi, Nuxti, and Aspi a standing room. For a portfolio post, Blogi asking Nuxti \"does this frontmatter still parse?\" is enough.",[113,2349,2350,2351,2354,2355,2357,2358,2361,2362,1506,2365,2368,2369,240],{},"Same agents from a shell: ",[222,2352,2353],{},"hermes -p blogi chat"," opens Blogi's profile, ",[222,2356,2011],{}," shows routines (jobs named ",[222,2359,2360],{},"[bot:\u003Cname>]","), and ",[222,2363,2364],{},"hermes profile list",[222,2366,2367],{},"hermes profile create"," inspect or add profiles. The files sit in ",[222,2370,1986],{},[108,2372,2374],{"id":2373},"what-worked-and-whats-still-rough","What worked and what's still rough",[113,2376,2377,2378,2381,2382,2385],{},"The split helps on the tasks I actually repeat. Blogi stays in ",[222,2379,2380],{},"content\u002Fblog\u002F"," and doesn't \"helpfully\" rewrite a Vue component. Nuxti can answer Nuxt UI questions with current component metadata. Aspi stays closer to feature-folder APIs. Switching bots is a click (or ",[222,2383,2384],{},"-p \u003Cname>","), which is less friction than I expected.",[113,2387,2388],{},"What's still rough:",[113,2390,2391,2392,2394],{},"Handoffs are not a pipeline. Per-invocation delivery means I am the scheduler. If I ",[222,2393,2049],{}," Aspi from Blogi and then keep talking to Blogi, I can miss the reply until I open Aspi's Bot Chat.",[113,2396,2397],{},"Capability lists drift. Aspi still has Nuxt and Unity MCPs. Blogi has X search. None of that is Bot Mode's fault. The New Agent dialog makes it easy to clone too much, and I haven't gone back through every checkbox.",[113,2399,2400,2401,2403],{},"Group chats have hard caps for a reason. I don't want three models politely passing in a circle while I wait. For my use, DM and ",[222,2402,2049],{}," are the whole workflow.",[113,2405,2406],{},"I still hop to Cursor or a stronger model when a turn gets gnarly. Bot Mode didn't change that. It changed how much junk sits in the prompt while the cheap loop does mechanical work.",[113,2408,2409,2410,2413],{},"Hidden Bots are display-only. ",[222,2411,2412],{},"@mentions"," still resolve, routines keep running, unread activity piles up behind an eye toggle. That's easy to forget if you \"hide\" a Bot you meant to retire. Delete Profile is the actual removal, and the default profile can't be deleted.",[108,2415,2417],{"id":2416},"faq","FAQ",[207,2419,2421],{"id":2420},"what-is-hermes-agent-bot-mode","What is Hermes Agent Bot Mode?",[113,2423,2424],{},"A desktop roster over Hermes profiles. Each Bot has a role, model, memory, skills, and avatar. Bots can run routines, sit in group chats, and message each other. The underlying object is still a profile.",[207,2426,2428],{"id":2427},"do-i-need-a-separate-plugin","Do I need a separate plugin?",[113,2430,2431],{},"Not on current desktop builds. Bot Mode is bundled and on by default. Settings → Plugins → Bots turns the UI off without deleting profiles.",[207,2433,2435],{"id":2434},"how-do-teammates-talk","How do teammates talk?",[113,2437,2438,2440,2441,2444],{},[222,2439,2049],{}," from a chat, or ",[222,2442,2443],{},"hermes -p \u003Cname> chat --in ~ -c \"Bot Chat\" --query-file \u003Cfile>"," into the canonical Bot Chat. The protocol is injected into that Bot Chat only.",[207,2446,2448],{"id":2447},"should-i-copy-this-three-bot-split","Should I copy this three-bot split?",[113,2450,2451],{},"Only if your week splits that way. One specialist is already a win over a single overloaded profile. Start with the domain that keeps polluting the others.",[108,2453,2455],{"id":2454},"where-this-sits-for-me","Where this sits for me",[113,2457,2458],{},"This is the setup on my machine today: three named Bots, domain-split skills, MCP still a bit messy, handoffs that I watch. Cheap enough to keep. Unfinished on purpose.",[113,2460,2461,2462,2466,2467,240],{},"If you're already on Hermes, the Bots tab is probably sitting next to Sessions. The docs to read first: ",[124,2463,2465],{"href":1953,"rel":2464},[130],"Bot Mode",". The prior experiment, before I split the roster, is the ",[124,2468,2469],{"href":42},"Hermes Agent + DeepSeek lab note",[770,2471,2472],{},"html pre.shiki code .sR7ES, html code.shiki .sR7ES{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sFhLe, html code.shiki .sFhLe{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .siCPE, html code.shiki .siCPE{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}",{"title":220,"searchDepth":252,"depth":258,"links":2474},[2475,2476,2477,2482,2483,2484,2490],{"id":1979,"depth":252,"text":1980},{"id":2056,"depth":252,"text":2057},{"id":2088,"depth":252,"text":2089,"children":2478},[2479,2480,2481],{"id":2102,"depth":258,"text":1964},{"id":2132,"depth":258,"text":1968},{"id":2171,"depth":258,"text":1972},{"id":2225,"depth":252,"text":2226},{"id":2373,"depth":252,"text":2374},{"id":2416,"depth":252,"text":2417,"children":2485},[2486,2487,2488,2489],{"id":2420,"depth":258,"text":2421},{"id":2427,"depth":258,"text":2428},{"id":2434,"depth":258,"text":2435},{"id":2447,"depth":258,"text":2448},{"id":2454,"depth":252,"text":2455},"How I run Hermes Agent Bot Mode with three specialist bots (Blogi, Nuxti, Aspi): what a Bot is, how they message each other, and what still feels unfinished.",{"src":2493},"\u002Fimages\u002Fhermes-bot-mode.svg",{"sitemap":2495,"schemaOrg":2496},{"lastmod":49},[2497],{"type":979,"headline":1935,"author":2498,"datePublished":49},{"type":982,"name":983},{"keywords":2500,"title":1935,"description":2491},"hermes agent bot mode, hermes agent teammates, multi-agent setup, bot-to-bot messaging, hermes profiles","blog\u002Fhermes-bot-mode","NRX4ORSgyJLHgjM_6urPzDVy5V49BOsnP1ukQQSVatk",1787129549331]