<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Ivan Dachev</title>
        <description>Ivan Dachev&apos;s journey through his current incarnation path.</description>
        <link>https://ivandachev.com/</link>
        <atom:link href="https://ivandachev.com/feed.xml" rel="self" type="application/rss+xml"/>
        <pubDate>Tue, 03 Nov 2026 16:19:37 +0000</pubDate>
        <lastBuildDate>Tue, 03 Nov 2026 16:19:37 +0000</lastBuildDate>
        <generator>Jekyll v4.3.4</generator>
        
            <item>
                <title>AI Workshop for Law Firms</title>
                <description>&lt;p&gt;I run a hands-on workshop for law firms in Bulgaria that want to use AI in their daily work:
contract reviews, case chronologies, research notes and letters to clients. We work with
&lt;strong&gt;Claude Cowork in Claude Desktop&lt;/strong&gt; and &lt;strong&gt;Gemini Notebook (formerly NotebookLM)&lt;/strong&gt;. The AI writes the
draft, and the lawyer checks and signs it.&lt;/p&gt;

&lt;p&gt;The principles are the same as in my &lt;a href=&quot;/blog/ai-coding-workshop&quot;&gt;AI Coding Workshop&lt;/a&gt; for software
teams: short instructions for the AI, a small checked set of tools, a written assignment before the
work, a human review and learning from every session. There is no code here. We work with a folder
of case documents.&lt;/p&gt;

&lt;p&gt;Claude Cowork is the mode in which Claude works with the files in a folder you choose. Since
16.09.2026 it is part of the normal conversation in Claude, and you no longer pick it separately
(&lt;a href=&quot;https://claude.com/blog/cowork-is-now-claude&quot;&gt;Anthropic&lt;/a&gt;). Gemini Notebook is Google’s tool for
working on the documents you upload. Google renamed NotebookLM to Gemini Notebook on 16.07.2026
(&lt;a href=&quot;https://blog.google/innovation-and-ai/products/gemini-notebook/notebooklm-gemini-notebook/&quot;&gt;Google&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;why-now&quot;&gt;Why Now&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;AI literacy under Article 4 of the EU AI Act.&lt;/strong&gt; The duty applies from 2.02.2025, and supervision
from 2.08.2026. It also covers organisations that use AI systems in their work, and it concerns the
people who use them on their behalf. According to the European Commission, no certificate is
needed, no specific level is required, and the organisation can keep an internal record of the
trainings. The Digital Omnibus amendments are in force since mid-July 2026
(&lt;a href=&quot;https://digital-strategy.ec.europa.eu/en/faqs/ai-literacy-questions-answers&quot;&gt;European Commission, AI literacy Q&amp;amp;A&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CCBE guidance for lawyers (2 October 2025).&lt;/strong&gt; No personal, confidential or other client data in
the AI tool unless appropriate safeguards are in place. Verify the output before you use it. Be
transparent with the client when you can reasonably expect an informed client to object, set
conditions or have reservations about the use of AI
(&lt;a href=&quot;https://www.ccbe.eu/fileadmin/speciality_distribution/public/documents/IT_LAW/ITL_Guides_recommendations/EN_ITL_20251002_CCBE-guide-on-the-use-of-the-use-of-generative-AI-for-lawyers.pdf&quot;&gt;CCBE guide on the use of generative AI by lawyers&lt;/a&gt;).
This is guidance from a professional body, not a binding rule in Bulgaria.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;UIA (International Association of Lawyers) guidelines, published in translation on the website
of the Bulgarian Supreme Bar Council.&lt;/strong&gt; Read the terms of the AI system. When possible, choose a
system that does not keep the information you enter. If that is not possible, anonymise the data
(&lt;a href=&quot;https://vas.bg/p/n/a/nasoki-uia-13638.pdf&quot;&gt;UIA guidelines&lt;/a&gt;). This too is guidance from a
professional body. Publication on the Bar Council’s website does not mean that the Council has
adopted it as rules. Claude and Gemini Notebook keep what you enter, so in the workshop we apply
the second part: anonymised documents and the firm’s approval.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A real example of the risk.&lt;/strong&gt; In the Al-Haroun case, decided together with Ayinde by an English
court on 6.06.2025, 18 of the 45 cited judgments do not exist
(&lt;a href=&quot;https://caselaw.nationalarchives.gov.uk/ewhc/admin/2025/1383&quot;&gt;Ayinde v Haringey, [2025] EWHC 1383 (Admin)&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The tools are already here.&lt;/strong&gt; On 12.05.2026 Anthropic released 12 legal plugins that are
available in Claude Cowork (&lt;a href=&quot;https://claude.com/blog/claude-for-the-legal-industry&quot;&gt;Anthropic&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;who-it-is-for&quot;&gt;Who It Is For&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Partners and managing lawyers who want shared rules for AI in the firm.&lt;/li&gt;
  &lt;li&gt;Lawyers and associates who work with many documents.&lt;/li&gt;
  &lt;li&gt;Assistants and office managers who prepare research notes and correspondence.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;format-and-duration&quot;&gt;Format and Duration&lt;/h2&gt;

&lt;p&gt;The workshop can run &lt;strong&gt;on-site&lt;/strong&gt; at your firm or &lt;strong&gt;online&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The format is &lt;strong&gt;2 sessions of 2 hours&lt;/strong&gt;. We set up the accounts before the first session, so the
time goes to practice. The program and the pace are adapted for each firm. We agree on the number of
participants and the language of the workshop in the first conversation.&lt;/p&gt;

&lt;h2 id=&quot;the-program&quot;&gt;The Program&lt;/h2&gt;

&lt;p&gt;The workshop follows one loop of ten steps. The last step feeds the first, so the firm’s rules get
better with every loop.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;theme-light-only&quot; src=&quot;/images/posts/software/2026/10/2026-10-29-ai-workshop-law-firms-cycle-en.jpg&quot; alt=&quot;Ten steps, one loop: from confidentiality to an AI policy&quot; /&gt;
&lt;img class=&quot;theme-dark-only&quot; src=&quot;/images/posts/software/2026/10/2026-10-29-ai-workshop-law-firms-cycle-en-dark.jpg&quot; alt=&quot;Ten steps, one loop: from confidentiality to an AI policy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The exercises are built on one fictional case: two versions of a contract, correspondence, a first-instance
judgment, notes from a client meeting and an NDA. The case documents are in Bulgarian.&lt;/p&gt;

&lt;h3 id=&quot;session-1--a-safe-foundation&quot;&gt;Session 1 – A Safe Foundation&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Confidentiality and account setup.&lt;/strong&gt; We separate four questions. Is the data used to train
models? Where does the work run – in the cloud or on your computer? Where does the model process
the documents? Where is the data stored? We also decide what never goes into the AI.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Instructions for Claude.&lt;/strong&gt; Short general instructions for the firm and instructions for the
case folder: who you are, which style and language you use, and what Claude never does. We write
the first version with Claude, then trim it by hand.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-29-ai-workshop-law-firms-001.jpg&quot; alt=&quot;Illustration: Claude saves instructions for the folder of the fictional case&quot; /&gt;
&lt;em&gt;An illustration of work in Claude Cowork with the fictional case, in Bulgarian. It is not a
screen from the real product.&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;One project per case.&lt;/strong&gt; A project in Cowork has its own files, instructions and memory. We work
on copies, not on originals. A separate project does not isolate the cases by itself: the
project’s memory is shared with conversations outside projects until you turn it off
(&lt;a href=&quot;https://support.claude.com/en/articles/14116274-organize-your-tasks-with-projects-in-claude-cowork&quot;&gt;Anthropic&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Legal plugins.&lt;/strong&gt; We show a small checked set. For example, the Legal plugin has commands for a
contract review and for a first triage of an NDA. Anthropic itself says that the outputs must be
reviewed by a licensed attorney (&lt;a href=&quot;https://claude.com/marketplace/plugins/legal&quot;&gt;Legal plugin&lt;/a&gt;). We
check whether a plugin fits Bulgarian law and adapt it.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Gemini Notebook – answers based on your sources.&lt;/strong&gt; We upload laws, case law and the case
documents. Google describes chat answers as answers with citations to the sources and says itself
that the tool can make mistakes (&lt;a href=&quot;https://support.google.com/notebooklm/answer/16164461&quot;&gt;Google&lt;/a&gt;).
So we do not accept an answer without a citation, and for every citation we check the passage and
whether the source is still in force. An Audio Overview in Bulgarian gives a quick review of the
case.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-29-ai-workshop-law-firms-004.jpg&quot; alt=&quot;Gemini Notebook answers in Bulgarian with numbered citations to both versions of the fictional contract&quot; /&gt;
&lt;em&gt;Gemini Notebook with the fictional case: an answer with numbered citations to the sources. On
the right is a two-minute Audio Overview in Bulgarian on the clauses that hurt the client.&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;session-2--draft-verify-process&quot;&gt;Session 2 – Draft, Verify, Process&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;An assignment before the work.&lt;/strong&gt; A template with the goal, what is out of scope, the sources
and what a good result looks like. Claude first proposes a plan, and you approve it.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Cowork writes the draft.&lt;/strong&gt; The main exercise: a comparison of two versions of a contract and a
chronology of the case from the correspondence. Claude asks for explicit permission before it
permanently deletes a file. The participant approves every deletion and everything that goes
out.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-29-ai-workshop-law-firms-002.jpg&quot; alt=&quot;Illustration: a table of the changed clauses between the two contract versions&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-29-ai-workshop-law-firms-003.jpg&quot; alt=&quot;Illustration: a case chronology with date, time, event and source&quot; /&gt;
&lt;em&gt;Illustrations of work in Claude Cowork with the fictional case, in Bulgarian. They are not
screens from the real product. The “Да провери адвокатът” (“for the lawyer to check”) notes mark
places for human review. We check the rest of the output too.&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Verification.&lt;/strong&gt; Not only the citations. We check that the facts are correct and complete and
that the result meets the assignment. Every reference is checked against the original. A second
review runs in a new session. The final word belongs to the lawyer who signs.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Learning and sharing.&lt;/strong&gt; A short retro after each task: what did I correct more than once?
Repeated corrections become rules or skills – saved instructions for a repeated task that Claude
reuses. Every shared skill has an owner and a version and is
checked before the whole firm gets it.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;An AI policy and a training record.&lt;/strong&gt; A one-page draft AI policy and a list of participants.
They are a supporting record of the measures under Article 4, not a guarantee of compliance. The
policy feeds step 1 in the next loop.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;your-own-documents&quot;&gt;Your Own Documents&lt;/h2&gt;

&lt;p&gt;The exercises use the fictional case. We use the firm’s own documents only if the firm approves it,
and under these conditions. They then replace the fictional contract in the second half of step 7
and in step 8.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Suitable accounts.&lt;/strong&gt; Claude on a Team or Enterprise plan, and a Google Workspace account for
Gemini Notebook. On Anthropic’s commercial plans, inputs and outputs are not used for training by
default. The exception is feedback (thumbs up or down), which the account owner can turn off
(&lt;a href=&quot;https://privacy.claude.com/en/articles/7996868-is-my-data-used-for-model-training&quot;&gt;Anthropic&lt;/a&gt;).
With a Workspace account, Google does not use the data in Gemini Notebook for training, and people
do not review it (&lt;a href=&quot;https://support.google.com/gemininotebook/answer/17004255&quot;&gt;Google&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Review before upload.&lt;/strong&gt; Templates and internal samples without client data come first.
Everything else is anonymised and approved by the firm.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Memory and feedback turned off.&lt;/strong&gt; Memory is turned off for the project. The owner turns
feedback off for the whole organisation (“Rate chats” in Organization settings &amp;gt; Data and
Privacy). Both happen before the firm’s documents go in.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No passwords or trade secrets&lt;/strong&gt;, under any circumstances.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Licences.&lt;/strong&gt; Texts from paid legal databases go in only if the licence explicitly allows uploading
and processing in another service. Otherwise we use official public sources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is important to be clear about what “local” means. In Cowork the work runs either in the cloud, on
Anthropic’s servers, or locally, on your computer. “Local” only means that the files and the work
itself stay on the computer. To read a document, the model still receives its content on Anthropic’s
servers. So “local” does not mean that the data never leaves the computer.&lt;/p&gt;

&lt;p&gt;Since 6.10.2026, new tasks on the Pro and Max plans run in the cloud
(&lt;a href=&quot;https://support.claude.com/en/articles/15520349-use-claude-cowork-on-web-desktop-and-mobile&quot;&gt;Anthropic&lt;/a&gt;).
On the Team plan the owner can turn cloud sessions off. In local sessions, the conversation history
stays on the users’ computers
(&lt;a href=&quot;https://support.claude.com/en/articles/13455879-use-claude-cowork-on-team-and-enterprise-plans&quot;&gt;Anthropic&lt;/a&gt;).
Anthropic states that the data of its commercial products is stored in the US
(&lt;a href=&quot;https://privacy.claude.com/en/articles/7996890-where-are-your-servers-located-do-you-host-your-models-on-eu-servers&quot;&gt;Anthropic&lt;/a&gt;).
The GDPR assessment – the data processing agreement with the provider and the basis for a transfer
outside the EU – belongs to the firm. We raise it as a question in step 1, but the workshop does not
replace it.&lt;/p&gt;

&lt;p&gt;These measures reduce the risk, but they are not a guarantee of confidentiality: a plan on which the
data is not used for training, feedback and memory turned off, anonymised documents and the firm’s
approval. The firm decides whether they are enough for the specific documents and for its
professional duties.&lt;/p&gt;

&lt;h2 id=&quot;what-to-expect&quot;&gt;What to Expect&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Practice on a fictional case.&lt;/strong&gt; Every participant goes through the whole loop with real tools,
with no risk to client confidentiality.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A setup that stays in the firm.&lt;/strong&gt; Instructions for Claude, an assignment template and the first
shared skills.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A habit of verification.&lt;/strong&gt; Every citation and every fact is checked against the original.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A draft AI policy&lt;/strong&gt; and a list of participants as a supporting record under Article 4.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Room for questions.&lt;/strong&gt; Every session has time for your questions and typical situations, without
client data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-participants-need&quot;&gt;What Participants Need&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;A laptop with Claude Desktop installed.&lt;/li&gt;
  &lt;li&gt;A paid Claude plan. For the firm’s own documents – Team or Enterprise.&lt;/li&gt;
  &lt;li&gt;A Google account. For the firm’s own documents – Google Workspace.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;get-in-touch&quot;&gt;Get in Touch&lt;/h2&gt;

&lt;p&gt;The program, the pace and the examples are adapted for each firm. For dates, format and price,
please &lt;a href=&quot;/contact/&quot;&gt;send me a message&lt;/a&gt; or write to me on
&lt;a href=&quot;https://www.linkedin.com/in/ivan-dachev-a506041a&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The information about the products and the rules is as of 29.10.2026.&lt;/em&gt;&lt;/p&gt;
</description>
                <pubDate>Thu, 29 Oct 2026 05:00:00 +0000</pubDate>
                <link>https://ivandachev.com/blog/ai-workshop-law-firms</link>
                <guid isPermaLink="true">https://ivandachev.com/blog/ai-workshop-law-firms</guid>
                
                <category>software</category>
                
                
            </item>
        
            <item>
                <title>AI Coding Workshop</title>
                <description>&lt;p&gt;I run a hands-on workshop for software teams that want to move from chaotic experiments with
prompts to a clear, repeatable workflow with AI coding agents. I show it mainly with Claude Code,
and the same workflow works for teams on GitHub Copilot.&lt;/p&gt;

&lt;p&gt;So far I have run it in more than 7 companies, among them:&lt;/p&gt;

&lt;div class=&quot;logo-strip&quot;&gt;
  &lt;a href=&quot;https://www.invendagroup.com/&quot; title=&quot;Invenda Group&quot;&gt;&lt;img class=&quot;theme-light-only&quot; src=&quot;/images/posts/software/2026/10/2026-10-25-ai-coding-workshop-logo-invenda.svg&quot; alt=&quot;Invenda Group&quot; /&gt;&lt;img class=&quot;theme-dark-only&quot; src=&quot;/images/posts/software/2026/10/2026-10-25-ai-coding-workshop-logo-invenda-dark.svg&quot; alt=&quot;Invenda Group&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;https://www.bosch.bg/our-company/bosch-in-bulgaria/bosch-digital/&quot; title=&quot;Bosch Digital&quot;&gt;&lt;img class=&quot;theme-light-only&quot; src=&quot;/images/posts/software/2026/10/2026-10-25-ai-coding-workshop-logo-bosch.svg&quot; alt=&quot;Bosch Digital&quot; /&gt;&lt;img class=&quot;theme-dark-only&quot; src=&quot;/images/posts/software/2026/10/2026-10-25-ai-coding-workshop-logo-bosch-dark.svg&quot; alt=&quot;Bosch Digital&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;https://www.fourth.com/&quot; title=&quot;Fourth&quot;&gt;&lt;img class=&quot;theme-light-only&quot; src=&quot;/images/posts/software/2026/10/2026-10-25-ai-coding-workshop-logo-fourth.svg&quot; alt=&quot;Fourth&quot; /&gt;&lt;img class=&quot;theme-dark-only&quot; src=&quot;/images/posts/software/2026/10/2026-10-25-ai-coding-workshop-logo-fourth-dark.svg&quot; alt=&quot;Fourth&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;https://ship.cars/&quot; title=&quot;Ship.Cars&quot;&gt;&lt;img class=&quot;theme-light-only&quot; src=&quot;/images/posts/software/2026/10/2026-10-25-ai-coding-workshop-logo-shipcars.svg&quot; alt=&quot;Ship.Cars&quot; /&gt;&lt;img class=&quot;theme-dark-only&quot; src=&quot;/images/posts/software/2026/10/2026-10-25-ai-coding-workshop-logo-shipcars-dark.svg&quot; alt=&quot;Ship.Cars&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;You can get a taste of the content from my talks at the
&lt;a href=&quot;/blog/basscom-ai-conf-claude-code-for-experts&quot;&gt;BASSCOM AI Conference 2026&lt;/a&gt; and the
&lt;a href=&quot;/blog/cotransition-coding-with-ai-agents&quot;&gt;CoTransition meetup&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;who-it-is-for&quot;&gt;Who It Is For&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Development teams that already use AI agents, or are about to start.&lt;/li&gt;
  &lt;li&gt;Teams on Claude Code, GitHub Copilot, or both.&lt;/li&gt;
  &lt;li&gt;Tech leads and architects who want one shared setup and clear rules for the whole team.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;format-and-duration&quot;&gt;Format and Duration&lt;/h2&gt;

&lt;p&gt;The workshop can run &lt;strong&gt;on-site&lt;/strong&gt; at your office or &lt;strong&gt;online&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The usual format is &lt;strong&gt;2 sessions of 2 hours&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Some teams need a slower pace. For them I split it into &lt;strong&gt;4 sessions of 1.5 hours&lt;/strong&gt;. The final plan
depends on the team: how fast they pick up the new workflow, how much experience they have with AI
agents, and who is in the room – developers, QA, tech leads or managers.&lt;/p&gt;

&lt;p&gt;Before the workshop we agree on the technology stack (for example Java, Angular, Python), so the
examples and the setup match your projects.&lt;/p&gt;

&lt;h2 id=&quot;the-program&quot;&gt;The Program&lt;/h2&gt;

&lt;p&gt;The workshop follows one loop of ten steps. The last step feeds the first, so the setup gets better
with every session.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-002.jpg&quot; alt=&quot;Ten steps, one loop&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Context files – &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AGENTS.md&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt;.&lt;/strong&gt; Keep them short, link docs instead of copying
them, include the build and test commands and the “never do” rules. Generate a first version with
the agent, then trim it by hand. Add per-module files for bigger repos and monorepos. Test it: ask
the agent to explain the project and check the answer.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Skills and MCP servers.&lt;/strong&gt; Install the right ones for your stack, check them for security and
enable only what the project needs. Start with a small base set and configure it at project
level, so the whole team gets the same setup. Too many tools make the agent slower and less
accurate.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Jira and GitHub in the workflow.&lt;/strong&gt; Connect the external tools with tokens with minimum rights,
read-only where possible. The flow is Jira ticket → spec → branch → pull request linked back to
the ticket. Decide what the agent may do alone and what needs a human approval.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Planning and specification.&lt;/strong&gt; Let the agent assess the repo scope first. Use a spec template:
goal, non-goals, acceptance criteria, test plan. One spec per area, split cross-repo work, trim
over-engineered plans. Stop at the spec and review it in a fresh session before any code.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Agents, subagents and the advisor.&lt;/strong&gt; Use subagents for parallel research and to keep the main
context clean. One agent or session per spec. Avoid too many agents – it makes it harder to track
decisions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Tests first (TDD), one step from the plan at a time, a commit after each
step, and hooks for lint and tests. The agent must not change tests to make them pass without
approval. Use git worktrees for parallel agents, and start a fresh session when the agent goes in
circles.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Verification and code review.&lt;/strong&gt; CI must pass: build, tests, lint, coverage. Architecture tests
(for example ArchUnit) check the clean architecture rules automatically. The AI reviews in a new
session first, then a human owns the final review.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Learning from sessions.&lt;/strong&gt; A short retro after each session: what did I correct more than once?
Repeated corrections become rules or skills. Clean the files regularly, so they don’t grow too
big.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Private plugins and a marketplace.&lt;/strong&gt; Package the knowledge that works into private plugins and
skills. Decide what stays in the repo and what becomes company-wide. Give each plugin an owner
and a version, and test skills before publishing them to the team.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Same workflow for Copilot.&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AGENTS.md&lt;/code&gt; is the shared base. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; and the Copilot
instructions both point to it. We go through which steps work the same and where Copilot
differs.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;what-to-expect&quot;&gt;What to Expect&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Hands-on work, not only slides.&lt;/strong&gt; We work on real examples, and where possible on your own
repositories.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A setup the team keeps.&lt;/strong&gt; Each team leaves with working context files, a base set of skills and
tools configured at project level, and a spec template.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Clear safety rules.&lt;/strong&gt; Least-privilege tokens, what the agent may do alone, and where a human
approval is always needed – merge, deploy, production.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A loop that keeps improving.&lt;/strong&gt; The team learns how to turn its own repeated corrections into
rules and skills after the workshop ends.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Room for questions.&lt;/strong&gt; Every session has time for Q&amp;amp;A and for your own cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-participants-need&quot;&gt;What Participants Need&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;A laptop with Claude Code or GitHub Copilot installed and working.&lt;/li&gt;
  &lt;li&gt;Access to a repository to practice on – a real project or a sample one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;get-in-touch&quot;&gt;Get in Touch&lt;/h2&gt;

&lt;p&gt;The program, the pace and the examples are adapted for each team. For dates, format and price,
please &lt;a href=&quot;/contact/&quot;&gt;send me a message&lt;/a&gt; or write to me on
&lt;a href=&quot;https://www.linkedin.com/in/ivan-dachev-a506041a&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
</description>
                <pubDate>Sun, 25 Oct 2026 05:00:00 +0000</pubDate>
                <link>https://ivandachev.com/blog/ai-coding-workshop</link>
                <guid isPermaLink="true">https://ivandachev.com/blog/ai-coding-workshop</guid>
                
                <category>software</category>
                
                
            </item>
        
            <item>
                <title>Coding with AI Agents</title>
                <description>&lt;p&gt;On October 22, 2026, I was the guest at a live
&lt;a href=&quot;https://online.cotransition.net/products/communities/v2/cotransitionagilemanagement/meetup/1c034a2d-f33a-4cf6-bfb3-687d8bbeab77&quot;&gt;meetup of the CoTransition – Agile Management community&lt;/a&gt;
at Campus X (VISA Innovation Hub) in Sofia. The evening was about the difference between chaotic
experiments with prompts and building Claude Code into everyday engineering work, with real
examples from my work at Ship.Cars USA, followed by Q&amp;amp;A and discussion.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.cotransition.net/&quot;&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-cotransition-logo.png&quot; alt=&quot;CoTransition&quot; class=&quot;theme-light-only&quot; style=&quot;width: 320px&quot; /&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-cotransition-logo-dark.png&quot; alt=&quot;CoTransition&quot; class=&quot;theme-dark-only&quot; style=&quot;width: 320px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I opened with a short talk: &lt;strong&gt;Coding with AI Agents&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The main idea fits in one line:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Hand over the whole task. Give it a way to check. Own what ships.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;the-slides&quot;&gt;The Slides&lt;/h2&gt;

&lt;p&gt;You can go through the whole deck here. It plays by itself. Click in it to stop it and use the arrow keys:&lt;/p&gt;

&lt;div class=&quot;deck-player&quot; id=&quot;deck-images-posts-software-2026-10-2026-10-22-cotransition-coding-with-ai-agents-slides-html&quot;&gt;
  &lt;div class=&quot;deck-player__frame&quot;&gt;
    &lt;iframe class=&quot;reframe-off&quot; src=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-slides.html&quot; title=&quot;Coding with AI Agents&quot; allow=&quot;fullscreen&quot;&gt;&lt;/iframe&gt;
    &lt;button type=&quot;button&quot; class=&quot;deck-player__toggle deck-player__toggle--top-right&quot;&gt;⏸ Pause&lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
  (function () {
    const root = document.getElementById(&apos;deck-images-posts-software-2026-10-2026-10-22-cotransition-coding-with-ai-agents-slides-html&apos;);
    const frame = root.querySelector(&apos;iframe&apos;);
    const toggle = root.querySelector(&apos;.deck-player__toggle&apos;);
    const stepMs = 1250;
    const slideMs = 3000;
    const liveMs = 8000;
    const labelPlay = &apos;▶ Play&apos;;
    const labelPause = &apos;⏸ Pause&apos;;

    let timer = null;
    let userPaused = false;
    let visible = false;
    let slides = [];
    let slide = 0;
    let presses = 0;

    function deckWindow() {
      return frame.contentWindow;
    }

    function readSlides() {
      if (slides.length &gt; 0) {
        return;
      }
      try {
        const motion = deckWindow().document.getElementById(&apos;deck-motion&apos;);
        slides = JSON.parse(motion.textContent).slides.map((s) =&gt; ({
          steps: (s.steps || []).length || 1,
          live: (s.embeds || []).length &gt; 0,
        }));
      } catch (e) {
        slides = [];
      }
    }

    function syncSlide() {
      const now = parseInt(deckWindow().location.hash.slice(1), 10) || 1;
      if (now !== slide) {
        slide = now;
        presses = 0;
      }
      return slides[slide - 1] || { steps: 1, live: false };
    }

    function delay() {
      const current = syncSlide();
      if (presses &lt; current.steps - 1) {
        return stepMs;
      }
      return current.live ? liveMs : slideMs;
    }

    function pressKey(key) {
      deckWindow().document.dispatchEvent(new KeyboardEvent(&apos;keydown&apos;, { key: key, code: key, bubbles: true }));
    }

    function advance() {
      if (slide === slides.length &amp;&amp; presses &gt;= slides[slide - 1].steps - 1) {
        pressKey(&apos;Home&apos;);
        slide = 0;
        return;
      }
      presses++;
      pressKey(&apos;ArrowRight&apos;);
    }

    function schedule() {
      timer = setTimeout(function () {
        syncSlide();
        advance();
        schedule();
      }, delay());
    }

    function update() {
      const shouldPlay = visible &amp;&amp; !document.hidden &amp;&amp; !userPaused &amp;&amp; slides.length &gt; 0;
      if (shouldPlay &amp;&amp; !timer) {
        schedule();
      } else if (!shouldPlay &amp;&amp; timer) {
        clearTimeout(timer);
        timer = null;
      }
      toggle.hidden = slides.length === 0;
      toggle.textContent = userPaused ? labelPlay : labelPause;
    }

    function pauseByUser(event) {
      if (event.isTrusted &amp;&amp; !userPaused) {
        userPaused = true;
        update();
      }
    }

    toggle.addEventListener(&apos;click&apos;, function () {
      userPaused = !userPaused;
      update();
    });

    function onDeckLoad() {
      readSlides();
      deckWindow().addEventListener(&apos;keydown&apos;, pauseByUser, true);
      deckWindow().addEventListener(&apos;pointerdown&apos;, pauseByUser, true);
      update();
    }

    if (frame.contentDocument &amp;&amp; frame.contentDocument.readyState === &apos;complete&apos; &amp;&amp; deckWindow().location.href !== &apos;about:blank&apos;) {
      onDeckLoad();
    } else {
      frame.addEventListener(&apos;load&apos;, onDeckLoad);
    }

    document.addEventListener(&apos;visibilitychange&apos;, update);

    new IntersectionObserver(
      function (entries) {
        visible = entries[0].intersectionRatio &gt;= 0.5;
        update();
      },
      { threshold: 0.5 }
    ).observe(frame);
  })();
&lt;/script&gt;

&lt;p&gt;If the embedded view above does not load, open it as a standalone page or download a file:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-slides.html&quot;&gt;Open in the browser (HTML)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-slides.pdf&quot;&gt;Download PDF&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-slides.pptx&quot;&gt;Download PowerPoint (PPTX)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also showed
&lt;strong&gt;&lt;a href=&quot;https://mentorano.github.io/ai-marketplace-mentorano/captain/?lang=en&quot;&gt;Captain&lt;/a&gt;&lt;/strong&gt; – a Claude
Code plugin where one session commands a crew of background agents. It splits the work, runs the
agents in parallel, sends every diff to review and asks you only about what matters.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://mentorano.github.io/ai-marketplace-mentorano/captain/?lang=en&quot;&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-captain-banner.png&quot; alt=&quot;How the Captain works&quot; class=&quot;theme-light-only&quot; /&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-captain-banner-dark.png&quot; alt=&quot;How the Captain works&quot; class=&quot;theme-dark-only&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;what-changed-less-prompting-not-more&quot;&gt;What Changed: Less Prompting, Not More&lt;/h2&gt;

&lt;p&gt;The new models need less prompting, not more:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Start at medium effort.&lt;/strong&gt; Go higher only when you measure a real gain.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Long autonomous runs work&lt;/strong&gt; – hours, if the agent has a clear finish line.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Big context&lt;/strong&gt; – 500K to 1M tokens, depending on the model, and thinking is built in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you can delete lines like &lt;em&gt;“think carefully”&lt;/em&gt;, &lt;em&gt;“double-check your answer”&lt;/em&gt; or &lt;em&gt;“use a
subagent to verify”&lt;/em&gt; from your prompts.&lt;/p&gt;

&lt;h2 id=&quot;three-habits-for-every-session&quot;&gt;Three Habits for Every Session&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Whole task, clear finish line.&lt;/strong&gt; For example: &lt;em&gt;“Done means: every endpoint migrated, old
client deleted, tests pass.”&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Turn the effort dial, skip “think hard”.&lt;/strong&gt; Modern models always think. The effort setting
decides how much.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Read “needs your decision” first.&lt;/strong&gt; Put short IDs on every question, so you can answer
“Q2 yes, OP1 no”.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;ten-steps-one-loop&quot;&gt;Ten Steps, One Loop&lt;/h2&gt;

&lt;p&gt;The workflow is not tied to one tool. It works with Claude Code and with GitHub Copilot.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-002.jpg&quot; alt=&quot;Ten steps, one loop&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Context files&lt;/strong&gt; – short, with a stop rule. Test each line: would removing it cause a mistake?
If not, cut it.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Skills, MCP, plugins&lt;/strong&gt; – loaded on demand, few tools. Context is the scarce resource. Prefer
CLI tools like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gh&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcloud&lt;/code&gt;, and vet every plugin like a package.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Jira and GitHub&lt;/strong&gt; – from ticket to pull request, with least-privilege tokens. The agent drafts;
a human merges and changes statuses.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Spec and review&lt;/strong&gt; – a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SPEC.md&lt;/code&gt; with a finish line. Let Claude interview you, then build it in
a fresh session.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Agents and advisor&lt;/strong&gt; – delegate big work in parallel, and let an observer agent watch for
silent decisions and false success.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Build&lt;/strong&gt; – tests first, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TASKS.md&lt;/code&gt; that survives compaction, and hooks that lint and test
every change.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Verify&lt;/strong&gt; – green is not the same as verified. Review in layers, not in one gate.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Learn&lt;/strong&gt; – a repeated correction becomes a rule in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt;, a skill, a hook or a lint rule.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Marketplace&lt;/strong&gt; – package what works as a private plugin, with an owner and a version.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Copilot parity&lt;/strong&gt; – &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AGENTS.md&lt;/code&gt; as the shared base for Claude Code and Copilot.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 8 feeds step 1, so the loop gets better every time.&lt;/p&gt;

&lt;h2 id=&quot;tell-it-when-to-stop&quot;&gt;Tell It When to Stop&lt;/h2&gt;

&lt;p&gt;One rule I always add to every &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; is a stop rule. Keep going when nothing needs you. Stop
and ask when the agent is blocked, or before anything destructive.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-003.jpg&quot; alt=&quot;Tell it when to stop&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Production, deploy and push always need your explicit yes.&lt;/p&gt;

&lt;h2 id=&quot;people-where-the-risk-is&quot;&gt;People Where the Risk Is&lt;/h2&gt;

&lt;p&gt;Not every change needs the same review. The change sets the tier, not the author:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-004.jpg&quot; alt=&quot;People where the risk is&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Low risk&lt;/strong&gt; – docs, copy, additive changes behind a flag: no human once the checks are green.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Medium risk&lt;/strong&gt; – ordinary product changes: one human approval.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;High risk&lt;/strong&gt; – auth, billing, CI and the other risky paths you name: two human approvals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whoever prompted the change owns it. A bot approval never replaces a human one.&lt;/p&gt;

&lt;h2 id=&quot;your-checklist&quot;&gt;Your Checklist&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/10/2026-10-22-cotransition-coding-with-ai-agents-005.jpg&quot; alt=&quot;Your checklist&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Ask&lt;/strong&gt; – the whole task with a finish line, no “think hard” lines, model and effort set up front.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Long runs&lt;/strong&gt; – a stop rule in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt;, context and permissions set before you leave, parallel
work by default with the full test suite per batch.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Check&lt;/strong&gt; – a check the agent can run, an observer agent beside the main one, green is not
verified.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Team&lt;/strong&gt; – repeated asks become written rules, no TODO without evidence, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AGENTS.md&lt;/code&gt; as the shared
base.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of this is based on the
&lt;a href=&quot;https://code.claude.com/docs/en/best-practices&quot;&gt;Claude Code best practices&lt;/a&gt;, the Anthropic
prompting guides, and lessons from my own sessions.&lt;/p&gt;

&lt;h2 id=&quot;impressions-from-the-event&quot;&gt;Impressions from the Event&lt;/h2&gt;

&lt;p&gt;Mladen Tomov from CoTransition wrote a
&lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:ugcPost:7520385602358288384/&quot;&gt;LinkedIn post with photos from the evening&lt;/a&gt;.
He sums up the main takeaways: a clear task with a clear definition of “done”, decisions made in
advance about when AI stops and asks, verification on several levels, and repeated corrections that
become rules.&lt;/p&gt;

&lt;p&gt;Thank you to the CoTransition community for the invitation and for the good questions!&lt;/p&gt;
</description>
                <pubDate>Thu, 22 Oct 2026 17:00:00 +0000</pubDate>
                <link>https://ivandachev.com/blog/cotransition-coding-with-ai-agents</link>
                <guid isPermaLink="true">https://ivandachev.com/blog/cotransition-coding-with-ai-agents</guid>
                
                <category>software</category>
                
                
            </item>
        
            <item>
                <title>Claude Code for Experts at BASSCOM AI Conference 2026</title>
                <description>&lt;p&gt;On April 29, 2026, I spoke at the
&lt;a href=&quot;https://basscom-ai-conf.com/&quot;&gt;BASSCOM AI Conference 2026&lt;/a&gt; in Sofia, at Inter Expo Center. The
conference was a full day of hands-on AI for about 500 attendees: a special keynote from
Anthropic and six sessions with real tools and practices from the industry, no abstract debates.&lt;/p&gt;

&lt;p&gt;My session was &lt;strong&gt;Claude Code for Experts&lt;/strong&gt;: advanced techniques for people who already use
Claude Code every day and want to get more out of it.&lt;/p&gt;

&lt;h2 id=&quot;the-slides&quot;&gt;The Slides&lt;/h2&gt;

&lt;p&gt;You can go through the whole presentation here:&lt;/p&gt;

&lt;div style=&quot;margin-bottom: 0.5rem&quot;&gt;
&lt;iframe src=&quot;https://gamma.app/embed/6wvlu2jzln0021c&quot; style=&quot;width: 700px; max-width: 100%; height: 450px&quot; allow=&quot;fullscreen&quot; title=&quot;BASSCOM AI Conf - Claude Code&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;If the embedded view above does not load, use the PDF or PPTX file:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gamma.app/docs/BASSCOM-AI-Conf-Claude-Code-6wvlu2jzln0021c&quot;&gt;Open in Gamma&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/images/posts/software/2026/04/2026-04-29-basscom-ai-conf-claude-code-for-experts-slides.pdf&quot;&gt;Download PDF&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/images/posts/software/2026/04/2026-04-29-basscom-ai-conf-claude-code-for-experts-slides.pptx&quot;&gt;Download PowerPoint (PPTX)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-i-covered&quot;&gt;What I Covered&lt;/h2&gt;

&lt;p&gt;The talk had three parts: the toolbox, the coding workflow, and a set of smaller hacks.&lt;/p&gt;

&lt;h3 id=&quot;the-toolbox&quot;&gt;The Toolbox&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Agents&lt;/strong&gt; – from chat to autonomous development: plan, code, review, refine, with parallel
subagents doing the tasks.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Skills and rules&lt;/strong&gt; – reusable playbooks. They load automatically when they are relevant, or
you call them with a slash command. Some are bundled, some are your own, some come from the
community.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Subagents&lt;/strong&gt; – each one has an isolated context, its own prompt, tools and permissions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;MCP servers, plugins and the marketplace&lt;/strong&gt; – how to extend Claude Code and share what works.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Context management&lt;/strong&gt; – the context window is the scarce resource, so treat it like one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-coding-workflow&quot;&gt;The Coding Workflow&lt;/h3&gt;

&lt;p&gt;The core of my daily work is one loop: &lt;strong&gt;Plan → Code → Review → Refine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/04/2026-04-29-basscom-ai-conf-claude-code-for-experts-002.jpg&quot; alt=&quot;Plan, Code, Review, Refine&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Planning is a conversation, not a single prompt. I give the agent a task. The agent asks about
the open questions and I answer them. Then it builds the first plan and reviews it itself.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/04/2026-04-29-basscom-ai-conf-claude-code-for-experts-003.jpg&quot; alt=&quot;Plan Creation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After that comes the plan review. The AI shows its findings, I decide what is real, and the AI
fixes the issues. Only then does the code start.&lt;/p&gt;

&lt;p&gt;A few tools help a lot here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/obra/superpowers&quot;&gt;Superpowers&lt;/a&gt; skills – brainstorming, writing plans and
systematic debugging.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/gastownhall/beads&quot;&gt;Beads&lt;/a&gt; – persistent, git-native task memory across
sessions, with a dependency-aware queue of “ready” tasks. It survives context compaction.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;TDD&lt;/strong&gt; – red, green, refactor. A failing test first gives the agent a check it can run.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Put together, this becomes a full SDLC workflow that the agent can drive almost end to end:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2026/04/2026-04-29-basscom-ai-conf-claude-code-for-experts-004.jpg&quot; alt=&quot;Full SDLC Automation Workflow&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Create a git branch or worktree.&lt;/li&gt;
  &lt;li&gt;Build the plan context.&lt;/li&gt;
  &lt;li&gt;Split the plan into tasks.&lt;/li&gt;
  &lt;li&gt;Implement the tasks with TDD.&lt;/li&gt;
  &lt;li&gt;Run the tests and the verification.&lt;/li&gt;
  &lt;li&gt;Submit a pull request for review.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I also showed &lt;strong&gt;&lt;a href=&quot;https://worca.dev/&quot;&gt;worca&lt;/a&gt;&lt;/strong&gt;, an orchestrator that runs this pipeline with
several agents. The code is on GitHub:
&lt;a href=&quot;https://github.com/SinishaDjukic/worca-cc&quot;&gt;SinishaDjukic/worca-cc&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;more-hacks&quot;&gt;More Hacks&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Rename your sessions&lt;/strong&gt;, so you can find and resume them later.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Use a status line&lt;/strong&gt; – model, context usage and git branch, always visible.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Keep your user Claude config in git&lt;/strong&gt; – &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.claude&lt;/code&gt; with your skills, hooks and settings.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/rtk-ai/rtk&quot;&gt;RTK&lt;/a&gt;&lt;/strong&gt; – reduces the context that bash output takes.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Know your context window&lt;/strong&gt; –
&lt;a href=&quot;https://code.claude.com/docs/en/context-window&quot;&gt;Context Window Insights&lt;/a&gt; in the Claude Code docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-conference-video&quot;&gt;The Conference Video&lt;/h2&gt;

&lt;p&gt;BASSCOM published a video from the conference, with interviews with the speakers:&lt;/p&gt;

&lt;div style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin-bottom: 2rem;&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/B21Iw9PLhdU&quot; title=&quot;BASSCOM AI CONFERENCE 2026&quot; style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;&quot; allow=&quot;accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id=&quot;thanks&quot;&gt;Thanks&lt;/h2&gt;

&lt;p&gt;Thank you to BASSCOM and to everyone who came and asked questions. It was a great day with a lot
of practical talks from the other speakers too.&lt;/p&gt;
</description>
                <pubDate>Wed, 29 Apr 2026 15:00:00 +0000</pubDate>
                <link>https://ivandachev.com/blog/basscom-ai-conf-claude-code-for-experts</link>
                <guid isPermaLink="true">https://ivandachev.com/blog/basscom-ai-conf-claude-code-for-experts</guid>
                
                <category>software</category>
                
                
            </item>
        
            <item>
                <title>Grandma Sevda&apos;s Medenki!</title>
                <description>&lt;h1 id=&quot;grandma-sevdas-medenki&quot;&gt;Grandma Sevda’s Medenki!&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Eco, soft, organic, lovely sweets from the town of Knezha – the hit of the Northwest!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The classic Bulgarian recipe for medenki – fragrant honey and cinnamon cookies, sandwiched in pairs
with a walnut and butter filling. A favorite childhood flavor that never goes out of style.&lt;/p&gt;

&lt;h2 id=&quot;ingredients&quot;&gt;Ingredients&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;2 eggs&lt;/li&gt;
  &lt;li&gt;½ cup sugar&lt;/li&gt;
  &lt;li&gt;½ cup honey&lt;/li&gt;
  &lt;li&gt;½ cup vegetable oil&lt;/li&gt;
  &lt;li&gt;2 packets vanilla sugar&lt;/li&gt;
  &lt;li&gt;1 tsp baking soda&lt;/li&gt;
  &lt;li&gt;1 tsp cinnamon&lt;/li&gt;
  &lt;li&gt;Flour – as much as needed for a soft dough&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Whisk the eggs with the sugar.&lt;/li&gt;
  &lt;li&gt;Add the honey and oil and mix well.&lt;/li&gt;
  &lt;li&gt;Add the vanilla, baking soda, and cinnamon.&lt;/li&gt;
  &lt;li&gt;Gradually add the flour until you get a soft dough that doesn’t stick to your hands.&lt;/li&gt;
  &lt;li&gt;Shape small walnut-sized balls and arrange them on a baking tray lined with parchment paper.&lt;/li&gt;
  &lt;li&gt;Bake in a preheated oven at 180°C (355°F) until golden brown.&lt;/li&gt;
  &lt;li&gt;While the medenki are still warm, use a small spoon to hollow out the center of each cookie.
&lt;strong&gt;Save all the crumbs&lt;/strong&gt; – they are an important ingredient for the filling.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/cooking/2026/04/2026-04-17-medenki-honey-cookies-002.jpg&quot; alt=&quot;Medenki baking in the oven&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;filling&quot;&gt;Filling&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;1 cup fresh milk&lt;/li&gt;
  &lt;li&gt;125 g butter (1 stick)&lt;/li&gt;
  &lt;li&gt;½ cup ground walnuts&lt;/li&gt;
  &lt;li&gt;The crumbs hollowed out from the medenki&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;preparing-the-filling&quot;&gt;Preparing the Filling&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Mix the butter, walnuts, and crumbs together.&lt;/li&gt;
  &lt;li&gt;Gradually add the fresh milk until you get a thick, smooth mixture.&lt;/li&gt;
  &lt;li&gt;Fill the hollowed medenki with the filling and sandwich them together in pairs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/cooking/2026/04/2026-04-17-medenki-honey-cookies-003.jpg&quot; alt=&quot;Walnut and crumb filling&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/cooking/2026/04/2026-04-17-medenki-honey-cookies-004.jpg&quot; alt=&quot;Hollowed medenki ready for filling&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;result&quot;&gt;Result&lt;/h2&gt;

&lt;p&gt;The finished medenki are soft on the inside, with a slightly crispy crust on the outside and a rich
flavor of honey and cinnamon. The walnut and butter filling makes them even juicier and more
aromatic. They are perfect for a holiday table or to enjoy with coffee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The medenki must rest in the refrigerator for at least 24 hours so they can soften.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/cooking/2026/04/2026-04-17-medenki-honey-cookies-005.jpg&quot; alt=&quot;Medenki sandwiched in pairs&quot; /&gt;&lt;/p&gt;
</description>
                <pubDate>Fri, 17 Apr 2026 08:00:12 +0000</pubDate>
                <link>https://ivandachev.com/blog/medenki-honey-cookies</link>
                <guid isPermaLink="true">https://ivandachev.com/blog/medenki-honey-cookies</guid>
                
                <category>cooking</category>
                
                
            </item>
        
            <item>
                <title>Claude Input Notify: Never Miss a Claude Code Notification Again</title>
                <description>&lt;p&gt;Working with Claude Code in the terminal can sometimes lead to missed input notifications,
especially when
you’re multitasking or have multiple windows open. That’s why I created &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;claude-input-notify.sh&lt;/code&gt; - a
simple but effective shell script that creates visual notifications whenever Claude Code needs your
attention.&lt;/p&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;

&lt;p&gt;When using Claude Code, there are moments when it pauses and waits for user input - asking for
confirmation, additional information, or next steps. If you’re working in another window or focused
on a different task, you might miss these notifications, leaving Claude waiting indefinitely and
disrupting your workflow.&lt;/p&gt;

&lt;h2 id=&quot;the-solution&quot;&gt;The Solution&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;claude-input-notify.sh&lt;/code&gt; script uses Claude Code’s hooks system and automatically displays a
visual notification popup whenever Claude Code needs user input. This ensures
you never miss an important interaction point.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2025/08/2025-08-13-claude-input-notify-001.png&quot; alt=&quot;Claude Input Notification Dialog&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;key-features&quot;&gt;Key Features&lt;/h2&gt;

&lt;h3 id=&quot;smart-terminal-detection&quot;&gt;Smart Terminal Detection&lt;/h3&gt;

&lt;p&gt;The script uses multiple methods to find your active terminal window:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Searches for windows by process name (gnome-terminal, konsole, xterm, etc.)&lt;/li&gt;
  &lt;li&gt;Falls back to the most recently focused window if needed&lt;/li&gt;
  &lt;li&gt;Supports various terminal emulators&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;visual-notification-system&quot;&gt;Visual Notification System&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Displays a clean, modern dialog with the Claude Code logo&lt;/li&gt;
  &lt;li&gt;Shows clear messaging about what’s happening&lt;/li&gt;
  &lt;li&gt;Provides an “OK” button to quickly return to the terminal&lt;/li&gt;
  &lt;li&gt;Optional “Cancel” button for dismissing without action&lt;/li&gt;
  &lt;li&gt;Can also be dismissed with the ESC key (same as Cancel)&lt;/li&gt;
  &lt;li&gt;Displays custom messages from Claude Code when available&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;developer-friendly-options&quot;&gt;Developer-Friendly Options&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Debug mode&lt;/strong&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEBUG_MODE=1&lt;/code&gt; environment variable): Shows detailed information about window detection&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Test mode&lt;/strong&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEST_MODE=1&lt;/code&gt; environment variable): Triggers a test notification to verify setup&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Verbose output&lt;/strong&gt;: Helps troubleshoot any issues&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;installation-and-setup&quot;&gt;Installation and Setup&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;First, ensure you have the required dependencies:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;xdotool wmctrl yad jq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Download the script and logo from my:
&lt;a href=&quot;https://github.com/idachev/own-debian-configs/blob/master/claude-input-notify.sh&quot;&gt;own-debian-configs repository&lt;/a&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Download the notification script&lt;/span&gt;
wget https://raw.githubusercontent.com/idachev/own-debian-configs/master/claude-input-notify.sh &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; ~/bin/claude-input-notify.sh
&lt;span class=&quot;nb&quot;&gt;chmod&lt;/span&gt; +x ~/bin/claude-input-notify.sh

&lt;span class=&quot;c&quot;&gt;# Download the Claude logo (optional, but recommended for better visuals)&lt;/span&gt;
wget https://raw.githubusercontent.com/idachev/own-debian-configs/master/claude-logo.png &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; ~/bin/claude-logo.png
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Configure Claude to use the notification script automatically by editing
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.claude/settings.json&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hooks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Notification&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hooks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~/bin/claude-input-notify.sh&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This hooks configuration ensures that the notification script runs automatically whenever Claude
Code needs user input - no manual piping required!&lt;/p&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h2&gt;

&lt;p&gt;When configured as a Claude hook, the script is automatically triggered whenever Claude Code
needs user input. The process flow is:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Claude Code detects it needs user input and triggers the Notification hook&lt;/li&gt;
  &lt;li&gt;The script reads any JSON message from stdin to display custom notifications&lt;/li&gt;
  &lt;li&gt;Identifies the terminal window where Claude Code is running&lt;/li&gt;
  &lt;li&gt;Creates a notification dialog using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yad&lt;/code&gt; (Yet Another Dialog)&lt;/li&gt;
  &lt;li&gt;When you click “OK”, it automatically brings the terminal window to focus&lt;/li&gt;
  &lt;li&gt;ESC or Cancel simply dismisses the notification without switching focus&lt;/li&gt;
  &lt;li&gt;Returns you right where you need to be to continue your interaction&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;advanced-usage&quot;&gt;Advanced Usage&lt;/h2&gt;

&lt;h3 id=&quot;debug-mode&quot;&gt;Debug Mode&lt;/h3&gt;

&lt;p&gt;To debug window detection issues, run the script manually with the debug environment variable:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;DEBUG_MODE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 ~/bin/claude-input-notify.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;test-the-notification&quot;&gt;Test the Notification&lt;/h3&gt;

&lt;p&gt;To verify everything is working:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;TEST_MODE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 ~/bin/claude-input-notify.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;technical-implementation&quot;&gt;Technical Implementation&lt;/h2&gt;

&lt;p&gt;The script leverages several Linux utilities:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;xdotool&lt;/strong&gt;: For window manipulation and focus management&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;wmctrl&lt;/strong&gt;: As a fallback for window operations&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;yad&lt;/strong&gt;: For creating the GTK+ dialog&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;pgrep/ps&lt;/strong&gt;: For process detection&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;jq&lt;/strong&gt;: Optional JSON parser for extracting custom messages from Claude Code hooks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The script reads JSON data from stdin when triggered by Claude Code hooks, allowing it to extract
and display custom messages. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jq&lt;/code&gt; is not available, it falls back to basic regex extraction.&lt;/p&gt;

&lt;p&gt;The notification can use either an external Claude logo file (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;claude-logo.png&lt;/code&gt;) if available, or
falls back to an embedded base64-encoded logo. This makes the script flexible - it works out of the
box but looks even better with the custom logo file.&lt;/p&gt;

&lt;h2 id=&quot;benefits&quot;&gt;Benefits&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Never miss notifications&lt;/strong&gt;: Stay aware of when Claude needs your input&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Improved workflow&lt;/strong&gt;: Seamlessly switch between tasks without losing track&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Visual feedback&lt;/strong&gt;: Clear, impossible-to-miss notifications&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Easy integration&lt;/strong&gt;: Works with any terminal setup&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Lightweight&lt;/strong&gt;: Minimal resource usage, runs only when needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;where-to-get-it&quot;&gt;Where to Get It&lt;/h2&gt;

&lt;p&gt;The complete solution including the script and logo file is available in my GitHub repository:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt;:
&lt;a href=&quot;https://github.com/idachev/own-debian-configs&quot;&gt;own-debian-configs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Script&lt;/strong&gt;:
&lt;a href=&quot;https://github.com/idachev/own-debian-configs/blob/master/claude-input-notify.sh&quot;&gt;claude-input-notify.sh&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Logo&lt;/strong&gt;:
&lt;a href=&quot;https://github.com/idachev/own-debian-configs/blob/master/claude-logo.png&quot;&gt;claude-logo.png&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This simple utility has significantly improved my workflow when working with Claude Code. By
leveraging Claude’s built-in hooks system, it integrates seamlessly without requiring any complex
setup or background processes. It’s one of those small tools that solves a specific problem
elegantly.&lt;/p&gt;

&lt;p&gt;If you’re a frequent Claude Code user working in the terminal, give &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;claude-input-notify.sh&lt;/code&gt; a try.
Combined with Claude’s hooks configuration, it provides a frictionless way to stay engaged with your
AI assistant, ensuring you never leave Claude waiting for your input again!&lt;/p&gt;
</description>
                <pubDate>Wed, 13 Aug 2025 07:00:00 +0000</pubDate>
                <link>https://ivandachev.com/blog/claude-input-notify-terminal-helper</link>
                <guid isPermaLink="true">https://ivandachev.com/blog/claude-input-notify-terminal-helper</guid>
                
                <category>software</category>
                
                
            </item>
        
            <item>
                <title>Building a Serverless Contact Form with Cloudflare Pages Functions and KV Store</title>
                <description>&lt;p&gt;&lt;strong&gt;Cloudflare Pages Functions and KV Store&lt;/strong&gt; provide a powerful serverless solution for building
contact forms without traditional backend infrastructure. This post details how to implement a secure,
scalable contact form using these technologies.&lt;/p&gt;

&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;

&lt;!-- @formatter:off --&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#table-of-contents&quot; id=&quot;markdown-toc-table-of-contents&quot;&gt;Table of Contents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#why-cloudflare-pages-functions-and-kv-store&quot; id=&quot;markdown-toc-why-cloudflare-pages-functions-and-kv-store&quot;&gt;Why Cloudflare Pages Functions and KV Store?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#architecture-overview&quot; id=&quot;markdown-toc-architecture-overview&quot;&gt;Architecture Overview&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#implementation-guide&quot; id=&quot;markdown-toc-implementation-guide&quot;&gt;Implementation Guide&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#deployment&quot; id=&quot;markdown-toc-deployment&quot;&gt;Deployment&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cost-analysis&quot; id=&quot;markdown-toc-cost-analysis&quot;&gt;Cost Analysis&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#api-endpoints&quot; id=&quot;markdown-toc-api-endpoints&quot;&gt;API Endpoints&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#security-best-practices&quot; id=&quot;markdown-toc-security-best-practices&quot;&gt;Security Best Practices&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusion&quot; id=&quot;markdown-toc-conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- @formatter:on --&gt;

&lt;h2 id=&quot;why-cloudflare-pages-functions-and-kv-store&quot;&gt;Why Cloudflare Pages Functions and KV Store?&lt;/h2&gt;

&lt;p&gt;Traditional contact form solutions often require:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Dedicated backend servers&lt;/li&gt;
  &lt;li&gt;Database infrastructure&lt;/li&gt;
  &lt;li&gt;Email server configuration&lt;/li&gt;
  &lt;li&gt;Complex deployment pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cloudflare’s serverless stack eliminates these requirements while providing:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Zero Infrastructure Management&lt;/strong&gt;: No servers to maintain or scale&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Global Edge Network&lt;/strong&gt;: Code runs close to users worldwide&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Built-in Security&lt;/strong&gt;: DDoS protection, rate limiting, and CAPTCHA support&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cost Efficiency&lt;/strong&gt;: Pay-per-request pricing with generous free tier&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h2&gt;

&lt;p&gt;The solution consists of four main components:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Static Frontend&lt;/strong&gt;: HTML form hosted on Cloudflare Pages&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pages Function&lt;/strong&gt;: Serverless handler processing form submissions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;KV Store&lt;/strong&gt;: Distributed key-value storage for submission data&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Turnstile CAPTCHA&lt;/strong&gt;: Bot protection and spam prevention&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;implementation-guide&quot;&gt;Implementation Guide&lt;/h2&gt;

&lt;p&gt;The complete working example code is available on GitHub: &lt;a href=&quot;https://github.com/idachev/ivandachev-examples/tree/master/cloudflare-contact-form&quot;&gt;ivandachev-examples/cloudflare-contact-form&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;step-1-setting-up-cloudflare-pages&quot;&gt;Step 1: Setting Up Cloudflare Pages&lt;/h3&gt;

&lt;p&gt;First, create a new Cloudflare Pages project:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create project directory&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;contact-form-app
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;contact-form-app

&lt;span class=&quot;c&quot;&gt;# Initialize npm project&lt;/span&gt;
npm init &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Install dependencies&lt;/span&gt;
npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-D&lt;/span&gt; wrangler
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-2-creating-the-contact-form&quot;&gt;Step 2: Creating the Contact Form&lt;/h3&gt;

&lt;p&gt;Create a simple HTML form in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public/index.html&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;github-code-embed&quot; id=&quot;code-https-raw-githubusercontent-com-idachev-ivandachev-examples-master-cloudflare-contact-form-public-index-html&quot;&gt;
  &lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;Loading code...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;script&gt;
  (function () {
    const embedId = &apos;code-https-raw-githubusercontent-com-idachev-ivandachev-examples-master-cloudflare-contact-form-public-index-html&apos;;
    const codeUrl = &apos;https://raw.githubusercontent.com/idachev/ivandachev-examples/master/cloudflare-contact-form/public/index.html&apos;;
    const language = &apos;html&apos;;

    // Ensure Prism language components are loaded
    function loadPrismComponent(lang) {
      if (typeof Prism === &apos;undefined&apos;) return;

      // Check if language is already loaded
      if (Prism.languages[lang]) return;

      // Try to load the language component dynamically
      const script = document.createElement(&apos;script&apos;);
      script.src = `https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/components/prism-${lang}.min.js`;
      script.onload = function () {
        // Re-highlight all code blocks after loading the component
        Prism.highlightAll();
      };
      document.head.appendChild(script);
    }

    fetch(codeUrl)
      .then((response) =&gt; {
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        return response.text();
      })
      .then((code) =&gt; {
        const codeElement = document.querySelector(`#${embedId} pre code`);
        codeElement.textContent = code;
        codeElement.className = `language-${language}`;

        // Load Prism language component if needed
        loadPrismComponent(language);

        // Re-highlight if using Prism.js
        if (typeof Prism !== &apos;undefined&apos;) {
          Prism.highlightElement(codeElement);
        }
        // Re-highlight if using highlight.js
        else if (typeof hljs !== &apos;undefined&apos;) {
          hljs.highlightElement(codeElement);
        }
      })
      .catch((error) =&gt; {
        console.error(&apos;Error loading code:&apos;, error);
        const codeElement = document.querySelector(`#${embedId} pre code`);
        codeElement.textContent = &apos;Error loading code. Please view it directly on GitHub.&apos;;
        codeElement.style.color = &apos;#d32f2f&apos;;
      });
  })();
&lt;/script&gt;

&lt;!-- Ensure Prism core and basic languages are loaded --&gt;
&lt;script&gt;
  if (typeof Prism === &apos;undefined&apos;) {
    // Load Prism core if not already loaded
    const prismCore = document.createElement(&apos;link&apos;);
    prismCore.rel = &apos;stylesheet&apos;;
    prismCore.href = &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/themes/prism.min.css&apos;;
    document.head.appendChild(prismCore);

    const prismScript = document.createElement(&apos;script&apos;);
    prismScript.src = &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/prism.min.js&apos;;
    document.head.appendChild(prismScript);

    // Load common components
    const prismAutoloader = document.createElement(&apos;script&apos;);
    prismAutoloader.src =
      &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/plugins/autoloader/prism-autoloader.min.js&apos;;
    prismAutoloader.onload = function () {
      if (typeof Prism !== &apos;undefined&apos; &amp;&amp; Prism.plugins &amp;&amp; Prism.plugins.autoloader) {
        Prism.plugins.autoloader.languages_path = &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/components/&apos;;
      }
    };
    document.head.appendChild(prismAutoloader);
  }
&lt;/script&gt;

&lt;style&gt;
  .github-code-embed {
    margin: 1em 0;
  }

  .github-code-embed pre {
    background-color: #f5f5f5;
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 1em;
    overflow-x: auto;
    /* Limit height to approximately 20 lines */
    max-height: 420px; /* 20 lines * ~21px per line */
    overflow-y: auto;
  }

  .github-code-embed pre code {
    background: none;
    padding: 0;
    border: none;
    font-size: 0.875em;
    line-height: 1.5;
    display: block;
  }

  /* Custom scrollbar styling for better appearance */
  .github-code-embed pre::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }

  .github-code-embed pre::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 4px;
  }

  .github-code-embed pre::-webkit-scrollbar-thumb {
    background: #888;
    border-radius: 4px;
  }

  .github-code-embed pre::-webkit-scrollbar-thumb:hover {
    background: #555;
  }

  /* Firefox scrollbar styling */
  .github-code-embed pre {
    scrollbar-width: thin;
    scrollbar-color: #888 #f1f1f1;
  }
&lt;/style&gt;

&lt;p&gt;View on GitHub: &lt;a href=&quot;https://github.com/idachev/ivandachev-examples/blob/master/cloudflare-contact-form/public/index.html&quot;&gt;index.html&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;step-3-implementing-the-pages-function&quot;&gt;Step 3: Implementing the Pages Function&lt;/h3&gt;

&lt;p&gt;Create the serverless handler in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;functions/api/contact.js&lt;/code&gt;. This implementation includes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;CORS support&lt;/strong&gt; for cross-origin requests&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rate limiting&lt;/strong&gt; (5 requests per minute per IP)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Configurable validation&lt;/strong&gt; with environment variables&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;API endpoints&lt;/strong&gt; - POST for submissions, GET for retrieval&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Turnstile CAPTCHA verification&lt;/strong&gt; for bot protection&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;github-code-embed&quot; id=&quot;code-https-raw-githubusercontent-com-idachev-ivandachev-examples-master-cloudflare-contact-form-functions-api-contact-js&quot;&gt;
  &lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;Loading code...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;script&gt;
  (function () {
    const embedId = &apos;code-https-raw-githubusercontent-com-idachev-ivandachev-examples-master-cloudflare-contact-form-functions-api-contact-js&apos;;
    const codeUrl = &apos;https://raw.githubusercontent.com/idachev/ivandachev-examples/master/cloudflare-contact-form/functions/api/contact.js&apos;;
    const language = &apos;javascript&apos;;

    // Ensure Prism language components are loaded
    function loadPrismComponent(lang) {
      if (typeof Prism === &apos;undefined&apos;) return;

      // Check if language is already loaded
      if (Prism.languages[lang]) return;

      // Try to load the language component dynamically
      const script = document.createElement(&apos;script&apos;);
      script.src = `https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/components/prism-${lang}.min.js`;
      script.onload = function () {
        // Re-highlight all code blocks after loading the component
        Prism.highlightAll();
      };
      document.head.appendChild(script);
    }

    fetch(codeUrl)
      .then((response) =&gt; {
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        return response.text();
      })
      .then((code) =&gt; {
        const codeElement = document.querySelector(`#${embedId} pre code`);
        codeElement.textContent = code;
        codeElement.className = `language-${language}`;

        // Load Prism language component if needed
        loadPrismComponent(language);

        // Re-highlight if using Prism.js
        if (typeof Prism !== &apos;undefined&apos;) {
          Prism.highlightElement(codeElement);
        }
        // Re-highlight if using highlight.js
        else if (typeof hljs !== &apos;undefined&apos;) {
          hljs.highlightElement(codeElement);
        }
      })
      .catch((error) =&gt; {
        console.error(&apos;Error loading code:&apos;, error);
        const codeElement = document.querySelector(`#${embedId} pre code`);
        codeElement.textContent = &apos;Error loading code. Please view it directly on GitHub.&apos;;
        codeElement.style.color = &apos;#d32f2f&apos;;
      });
  })();
&lt;/script&gt;

&lt;!-- Ensure Prism core and basic languages are loaded --&gt;
&lt;script&gt;
  if (typeof Prism === &apos;undefined&apos;) {
    // Load Prism core if not already loaded
    const prismCore = document.createElement(&apos;link&apos;);
    prismCore.rel = &apos;stylesheet&apos;;
    prismCore.href = &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/themes/prism.min.css&apos;;
    document.head.appendChild(prismCore);

    const prismScript = document.createElement(&apos;script&apos;);
    prismScript.src = &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/prism.min.js&apos;;
    document.head.appendChild(prismScript);

    // Load common components
    const prismAutoloader = document.createElement(&apos;script&apos;);
    prismAutoloader.src =
      &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/plugins/autoloader/prism-autoloader.min.js&apos;;
    prismAutoloader.onload = function () {
      if (typeof Prism !== &apos;undefined&apos; &amp;&amp; Prism.plugins &amp;&amp; Prism.plugins.autoloader) {
        Prism.plugins.autoloader.languages_path = &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/components/&apos;;
      }
    };
    document.head.appendChild(prismAutoloader);
  }
&lt;/script&gt;

&lt;style&gt;
  .github-code-embed {
    margin: 1em 0;
  }

  .github-code-embed pre {
    background-color: #f5f5f5;
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 1em;
    overflow-x: auto;
    /* Limit height to approximately 20 lines */
    max-height: 420px; /* 20 lines * ~21px per line */
    overflow-y: auto;
  }

  .github-code-embed pre code {
    background: none;
    padding: 0;
    border: none;
    font-size: 0.875em;
    line-height: 1.5;
    display: block;
  }

  /* Custom scrollbar styling for better appearance */
  .github-code-embed pre::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }

  .github-code-embed pre::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 4px;
  }

  .github-code-embed pre::-webkit-scrollbar-thumb {
    background: #888;
    border-radius: 4px;
  }

  .github-code-embed pre::-webkit-scrollbar-thumb:hover {
    background: #555;
  }

  /* Firefox scrollbar styling */
  .github-code-embed pre {
    scrollbar-width: thin;
    scrollbar-color: #888 #f1f1f1;
  }
&lt;/style&gt;

&lt;p&gt;View on GitHub: &lt;a href=&quot;https://github.com/idachev/ivandachev-examples/blob/master/cloudflare-contact-form/functions/api/contact.js&quot;&gt;contact.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key features in the code:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CORS headers configuration with allowed origins&lt;/li&gt;
  &lt;li&gt;Rate limiting using KV with automatic expiration&lt;/li&gt;
  &lt;li&gt;Input validation with configurable min/max lengths&lt;/li&gt;
  &lt;li&gt;API key authentication supporting both query parameter and header&lt;/li&gt;
  &lt;li&gt;Turnstile token verification with server-side validation&lt;/li&gt;
  &lt;li&gt;Comprehensive error handling with appropriate HTTP status codes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;step-4-configuring-kv-store&quot;&gt;Step 4: Configuring KV Store&lt;/h3&gt;

&lt;p&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wrangler.jsonc&lt;/code&gt; configuration file with KV namespace binding and environment variables:&lt;/p&gt;

&lt;div class=&quot;github-code-embed&quot; id=&quot;code-https-raw-githubusercontent-com-idachev-ivandachev-examples-master-cloudflare-contact-form-wrangler-jsonc&quot;&gt;
  &lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;Loading code...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;script&gt;
  (function () {
    const embedId = &apos;code-https-raw-githubusercontent-com-idachev-ivandachev-examples-master-cloudflare-contact-form-wrangler-jsonc&apos;;
    const codeUrl = &apos;https://raw.githubusercontent.com/idachev/ivandachev-examples/master/cloudflare-contact-form/wrangler.jsonc&apos;;
    const language = &apos;json&apos;;

    // Ensure Prism language components are loaded
    function loadPrismComponent(lang) {
      if (typeof Prism === &apos;undefined&apos;) return;

      // Check if language is already loaded
      if (Prism.languages[lang]) return;

      // Try to load the language component dynamically
      const script = document.createElement(&apos;script&apos;);
      script.src = `https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/components/prism-${lang}.min.js`;
      script.onload = function () {
        // Re-highlight all code blocks after loading the component
        Prism.highlightAll();
      };
      document.head.appendChild(script);
    }

    fetch(codeUrl)
      .then((response) =&gt; {
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        return response.text();
      })
      .then((code) =&gt; {
        const codeElement = document.querySelector(`#${embedId} pre code`);
        codeElement.textContent = code;
        codeElement.className = `language-${language}`;

        // Load Prism language component if needed
        loadPrismComponent(language);

        // Re-highlight if using Prism.js
        if (typeof Prism !== &apos;undefined&apos;) {
          Prism.highlightElement(codeElement);
        }
        // Re-highlight if using highlight.js
        else if (typeof hljs !== &apos;undefined&apos;) {
          hljs.highlightElement(codeElement);
        }
      })
      .catch((error) =&gt; {
        console.error(&apos;Error loading code:&apos;, error);
        const codeElement = document.querySelector(`#${embedId} pre code`);
        codeElement.textContent = &apos;Error loading code. Please view it directly on GitHub.&apos;;
        codeElement.style.color = &apos;#d32f2f&apos;;
      });
  })();
&lt;/script&gt;

&lt;!-- Ensure Prism core and basic languages are loaded --&gt;
&lt;script&gt;
  if (typeof Prism === &apos;undefined&apos;) {
    // Load Prism core if not already loaded
    const prismCore = document.createElement(&apos;link&apos;);
    prismCore.rel = &apos;stylesheet&apos;;
    prismCore.href = &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/themes/prism.min.css&apos;;
    document.head.appendChild(prismCore);

    const prismScript = document.createElement(&apos;script&apos;);
    prismScript.src = &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/prism.min.js&apos;;
    document.head.appendChild(prismScript);

    // Load common components
    const prismAutoloader = document.createElement(&apos;script&apos;);
    prismAutoloader.src =
      &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/plugins/autoloader/prism-autoloader.min.js&apos;;
    prismAutoloader.onload = function () {
      if (typeof Prism !== &apos;undefined&apos; &amp;&amp; Prism.plugins &amp;&amp; Prism.plugins.autoloader) {
        Prism.plugins.autoloader.languages_path = &apos;https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/components/&apos;;
      }
    };
    document.head.appendChild(prismAutoloader);
  }
&lt;/script&gt;

&lt;style&gt;
  .github-code-embed {
    margin: 1em 0;
  }

  .github-code-embed pre {
    background-color: #f5f5f5;
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 1em;
    overflow-x: auto;
    /* Limit height to approximately 20 lines */
    max-height: 420px; /* 20 lines * ~21px per line */
    overflow-y: auto;
  }

  .github-code-embed pre code {
    background: none;
    padding: 0;
    border: none;
    font-size: 0.875em;
    line-height: 1.5;
    display: block;
  }

  /* Custom scrollbar styling for better appearance */
  .github-code-embed pre::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }

  .github-code-embed pre::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 4px;
  }

  .github-code-embed pre::-webkit-scrollbar-thumb {
    background: #888;
    border-radius: 4px;
  }

  .github-code-embed pre::-webkit-scrollbar-thumb:hover {
    background: #555;
  }

  /* Firefox scrollbar styling */
  .github-code-embed pre {
    scrollbar-width: thin;
    scrollbar-color: #888 #f1f1f1;
  }
&lt;/style&gt;

&lt;p&gt;View on GitHub: &lt;a href=&quot;https://github.com/idachev/ivandachev-examples/blob/master/cloudflare-contact-form/wrangler.jsonc&quot;&gt;wrangler.jsonc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The configuration includes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;KV namespace binding for storing submissions&lt;/li&gt;
  &lt;li&gt;Allowed origins for CORS&lt;/li&gt;
  &lt;li&gt;Configurable validation limits&lt;/li&gt;
  &lt;li&gt;Comments for setting up the API key secret&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create the KV namespace and set up authentication:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create KV namespace using npm script&lt;/span&gt;
npm run kv:create
&lt;span class=&quot;c&quot;&gt;# Copy the generated ID to wrangler.jsonc&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Generate a secure API key&lt;/span&gt;
openssl rand &lt;span class=&quot;nt&quot;&gt;-hex&lt;/span&gt; 32

&lt;span class=&quot;c&quot;&gt;# Set the API key as a secret&lt;/span&gt;
npx wrangler pages secret put API_KEY &lt;span class=&quot;nt&quot;&gt;--project-name&lt;/span&gt; contact-form-app
&lt;span class=&quot;c&quot;&gt;# Enter the generated key when prompted&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Verify the secret was uploaded&lt;/span&gt;
npx wrangler pages secret list &lt;span class=&quot;nt&quot;&gt;--project-name&lt;/span&gt; contact-form-app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-5-configure-cloudflare-turnstile&quot;&gt;Step 5: Configure Cloudflare Turnstile&lt;/h3&gt;

&lt;p&gt;Turnstile provides CAPTCHA protection to prevent spam and bot submissions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Create a Turnstile site&lt;/strong&gt; in your Cloudflare dashboard:
    &lt;ul&gt;
      &lt;li&gt;Navigate to &lt;strong&gt;Turnstile&lt;/strong&gt; in the sidebar&lt;/li&gt;
      &lt;li&gt;Click &lt;strong&gt;Add Site&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;Configure your site with your domain(s)&lt;/li&gt;
      &lt;li&gt;Choose widget mode (Managed or Invisible)&lt;/li&gt;
      &lt;li&gt;Copy the &lt;strong&gt;Site Key&lt;/strong&gt; and &lt;strong&gt;Secret Key&lt;/strong&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Update your configuration&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;Set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TURNSTILE_SITE_KEY&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wrangler.jsonc&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Update the site key in your HTML form&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Set the secret key&lt;/strong&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx wrangler pages secret put TURNSTILE_SECRET_KEY &lt;span class=&quot;nt&quot;&gt;--project-name&lt;/span&gt; contact-form-app
&lt;span class=&quot;c&quot;&gt;# Enter your Turnstile secret key when prompted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Widget customization options&lt;/strong&gt;:
    &lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cf-turnstile&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-sitekey=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;YOUR_SITE_KEY&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-theme=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;light&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-size=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;normal&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For detailed Turnstile setup instructions, see
the &lt;a href=&quot;https://github.com/idachev/ivandachev-examples/blob/master/cloudflare-contact-form/TURNSTILE_SETUP.md&quot;&gt;TURNSTILE_SETUP.md&lt;/a&gt;
guide in the example repository.&lt;/p&gt;

&lt;h2 id=&quot;deployment&quot;&gt;Deployment&lt;/h2&gt;

&lt;p&gt;Deploy your contact form application:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Login to Cloudflare&lt;/span&gt;
wrangler login

&lt;span class=&quot;c&quot;&gt;# Deploy to Cloudflare Pages&lt;/span&gt;
npm run deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For local development:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Run development server on http://localhost:8788&lt;/span&gt;
npm run dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The example repository also includes development tools for code quality:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Format code with Prettier&lt;/span&gt;
npm run format

&lt;span class=&quot;c&quot;&gt;# Run ESLint for JavaScript linting&lt;/span&gt;
npm run lint

&lt;span class=&quot;c&quot;&gt;# Run Stylelint for CSS linting&lt;/span&gt;
npm run lint:css
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;cost-analysis&quot;&gt;Cost Analysis&lt;/h2&gt;

&lt;p&gt;Cloudflare’s pricing model for this solution:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Pages&lt;/strong&gt;: Free for unlimited requests&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Functions&lt;/strong&gt;: 100,000 requests/day free, then $0.50/million&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;KV Storage&lt;/strong&gt;: 100,000 reads/day free, 1,000 writes/day free&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;KV Operations&lt;/strong&gt;: $0.50/million reads, $5.00/million writes after free tier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a typical contact form receiving 1,000 submissions per month:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Monthly Cost&lt;/strong&gt;: $0 (within free tier)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scale Capacity&lt;/strong&gt;: Can handle millions of submissions without infrastructure changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;api-endpoints&quot;&gt;API Endpoints&lt;/h2&gt;

&lt;p&gt;The contact form provides these endpoints:&lt;/p&gt;

&lt;h3 id=&quot;submit-contact-form&quot;&gt;Submit Contact Form&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;POST&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/contact&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Body: JSON with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;message&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cf-turnstile-response&lt;/code&gt; fields&lt;/li&gt;
  &lt;li&gt;Requires valid Cloudflare Turnstile token&lt;/li&gt;
  &lt;li&gt;Rate limited to 5 submissions per minute per IP&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;get-submissions-requires-api-key&quot;&gt;Get Submissions (requires API key)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;GET&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/contact?api_key=YOUR_API_KEY&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GET&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/contact&lt;/code&gt; with header &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X-API-Key: YOUR_API_KEY&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Query parameters:
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;limit&lt;/code&gt;: Number of results per page (1-1000, default: 100)&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cursor&lt;/code&gt;: Pagination cursor for next page&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Returns JSON response with:
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;submissions&lt;/code&gt;: Array of submission objects&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list_complete&lt;/code&gt;: Boolean indicating if there are more results&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cursor&lt;/code&gt;: Cursor for next page (null if no more results)&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;count&lt;/code&gt;: Number of submissions in current page&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;check-api-status&quot;&gt;Check API Status&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;GET&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/contact&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Returns API status (no authentication required)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;security-best-practices&quot;&gt;Security Best Practices&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;CAPTCHA Protection&lt;/strong&gt;: Cloudflare Turnstile prevents bot submissions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Input Validation&lt;/strong&gt;: Always validate and sanitize user input&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rate Limiting&lt;/strong&gt;: Implement per-IP rate limiting (5 requests/minute)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CORS&lt;/strong&gt;: Configure appropriate CORS headers for allowed domains&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;API Security&lt;/strong&gt;: Use API keys for data access endpoints&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Encryption&lt;/strong&gt;: Use HTTPS for all communications&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Data Retention&lt;/strong&gt;: Implement automatic data expiration policies&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Token Security&lt;/strong&gt;: Turnstile tokens expire after 5 minutes and are single-use&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Cloudflare Pages Functions and KV Store provide a robust, scalable solution for contact forms that
eliminates traditional infrastructure complexity. This serverless approach offers:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Global Performance&lt;/strong&gt;: Edge deployment ensures low latency worldwide&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Automatic Scaling&lt;/strong&gt;: Handle traffic spikes without configuration&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cost Efficiency&lt;/strong&gt;: Pay only for what you use&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Developer Experience&lt;/strong&gt;: Simple deployment and maintenance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The combination of Pages Functions for compute and KV Store for persistence creates a complete
backend solution that’s perfect for contact forms and similar applications requiring simple data
collection and storage.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Have you built serverless applications with Cloudflare? Share your experiences and tips in the
comments below!&lt;/em&gt;&lt;/p&gt;
</description>
                <pubDate>Fri, 18 Jul 2025 21:00:00 +0000</pubDate>
                <link>https://ivandachev.com/blog/cloudflare-contact-form-kv-pages-functions</link>
                <guid isPermaLink="true">https://ivandachev.com/blog/cloudflare-contact-form-kv-pages-functions</guid>
                
                <category>software</category>
                
                
            </item>
        
            <item>
                <title>MCP Java Decompiler Server: Bridging AI Tools with Java Bytecode Analysis</title>
                <description>&lt;p&gt;&lt;strong&gt;MCP Java Decompiler Server&lt;/strong&gt; - a specialized server that allows AI agents to decompile and analyze
Java bytecode.&lt;/p&gt;

&lt;p&gt;I use this MCP when working with Claude Code to instruct it to decompile classes whose source code
is not available, so it can analyze and use them in the context of the current task I’ve given it.&lt;/p&gt;

&lt;h2 id=&quot;what-is-mcp-java-decompiler-server&quot;&gt;What is MCP Java Decompiler Server?&lt;/h2&gt;

&lt;p&gt;MCP Java Decompiler Server is a Node.js-based tool that provides AI agents with the ability to
decompile Java &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.class&lt;/code&gt; files, extract classes from JAR files, and analyze Java bytecode
programmatically. It uses the JavaScript port of the CFR decompiler to convert compiled Java
bytecode back into readable source code.&lt;/p&gt;

&lt;h2 id=&quot;key-features&quot;&gt;Key Features&lt;/h2&gt;

&lt;h3 id=&quot;multiple-decompilation-methods&quot;&gt;Multiple Decompilation Methods&lt;/h3&gt;

&lt;p&gt;The server supports three different ways to decompile Java code:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;File Path Decompilation&lt;/strong&gt;: Directly decompile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.class&lt;/code&gt; files from the filesystem.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Package Name Extraction&lt;/strong&gt;: Extract and decompile classes by their fully qualified names.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;JAR File Analysis&lt;/strong&gt;: Decompile specific classes from JAR archives.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;technical-capabilities&quot;&gt;Technical Capabilities&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Wide Java Support&lt;/strong&gt;: Compatible with all Java versions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No Java Runtime Required&lt;/strong&gt;: Runs purely on Node.js 16+ without needing a Java installation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;MCP-Compatible API&lt;/strong&gt;: Full integration with MCP-compatible AI tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;installation-and-setup&quot;&gt;Installation and Setup&lt;/h2&gt;

&lt;p&gt;The server offers multiple installation options suitable for different use cases:&lt;/p&gt;

&lt;h3 id=&quot;installing-in-ai-agents&quot;&gt;Installing in AI Agents&lt;/h3&gt;

&lt;p&gt;Claude code:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;claude mcp add javadc &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; project &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; npx &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; @idachev/mcp-javadc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Standard MCP JSON configuration:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;javadc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stdio&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;npx&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;args&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-y&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@idachev/mcp-javadc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;env&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;why-this-matters&quot;&gt;Why This Matters&lt;/h2&gt;

&lt;p&gt;This tool bridges a significant gap between AI agents and Java development workflows. When working
with compiled Java applications or third-party libraries, AI agents often encounter classes without
available source code. The server extracts and decompiles these classes, returning readable source
code that enables AI agents to understand and analyze the implementation.&lt;/p&gt;

&lt;h2 id=&quot;integration-with-ai-workflows&quot;&gt;Integration with AI Workflows&lt;/h2&gt;

&lt;p&gt;MCP Java Decompiler Server integrates seamlessly with MCP-compatible AI tools, allowing them to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Analyze JAR dependencies in Maven/Gradle projects.&lt;/li&gt;
  &lt;li&gt;Understand compiled code structure.&lt;/li&gt;
  &lt;li&gt;Provide insights into third-party library implementations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;get-started&quot;&gt;Get Started&lt;/h2&gt;

&lt;p&gt;MCP Java Decompiler Server is available on &lt;a href=&quot;https://github.com/idachev/mcp-javadc&quot;&gt;GitHub&lt;/a&gt; under the
ISC license. Whether you’re working with legacy Java code, analyzing dependencies, or building
AI-powered development tools, this server provides the bridge you need between AI assistants and
Java bytecode.&lt;/p&gt;

&lt;p&gt;Try it out with your favorite MCP-compatible AI tool and see how it can enhance your Java
development workflow!&lt;/p&gt;
</description>
                <pubDate>Fri, 27 Jun 2025 11:30:00 +0000</pubDate>
                <link>https://ivandachev.com/blog/mcp-java-decompiler-server</link>
                <guid isPermaLink="true">https://ivandachev.com/blog/mcp-java-decompiler-server</guid>
                
                <category>software</category>
                
                
            </item>
        
            <item>
                <title>Using Claude Code MCP with Atlassian: A Complete Guide to Documentation Generation</title>
                <description>&lt;h1 id=&quot;using-claude-code-mcp-with-atlassian-a-complete-guide-to-documentation-generation&quot;&gt;Using Claude Code MCP with Atlassian: A Complete Guide to Documentation Generation&lt;/h1&gt;

&lt;p&gt;The Model Context Protocol (MCP) has revolutionized how we integrate AI tools with external
services. In this post, I’ll show you how to set up Claude Code MCP with Atlassian and demonstrate a
practical use case: automatically generating comprehensive documentation for OpenTelemetry
implementation in your codebase.&lt;/p&gt;

&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;

&lt;!-- @formatter:off --&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#table-of-contents&quot; id=&quot;markdown-toc-table-of-contents&quot;&gt;Table of Contents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#setting-up-claude-code-mcp-with-atlassian&quot; id=&quot;markdown-toc-setting-up-claude-code-mcp-with-atlassian&quot;&gt;Setting Up Claude Code MCP with Atlassian&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#real-world-use-case-opentelemetry-documentation&quot; id=&quot;markdown-toc-real-world-use-case-opentelemetry-documentation&quot;&gt;Real-World Use Case: OpenTelemetry Documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#key-benefits-of-this-approach&quot; id=&quot;markdown-toc-key-benefits-of-this-approach&quot;&gt;Key Benefits of This Approach&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#best-practices-for-claude-code-mcp--atlassian&quot; id=&quot;markdown-toc-best-practices-for-claude-code-mcp--atlassian&quot;&gt;Best Practices for Claude Code MCP + Atlassian&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#advanced-use-cases&quot; id=&quot;markdown-toc-advanced-use-cases&quot;&gt;Advanced Use Cases&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusion&quot; id=&quot;markdown-toc-conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- @formatter:on --&gt;

&lt;h2 id=&quot;setting-up-claude-code-mcp-with-atlassian&quot;&gt;Setting Up Claude Code MCP with Atlassian&lt;/h2&gt;

&lt;p&gt;Getting started with Claude Code MCP and Atlassian is straightforward. Here’s the command to add the
Atlassian MCP server:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;claude mcp add atlassian &lt;span class=&quot;nt&quot;&gt;--transport&lt;/span&gt; sse &lt;span class=&quot;s2&quot;&gt;&quot;https://mcp.atlassian.com/v1/sse&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--scope&lt;/span&gt; user
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This command:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Adds the Atlassian MCP server to your Claude Code configuration&lt;/li&gt;
  &lt;li&gt;Uses Server-Sent Events (SSE) as the transport mechanism&lt;/li&gt;
  &lt;li&gt;Connects to the official Atlassian MCP endpoint&lt;/li&gt;
  &lt;li&gt;Sets the scope to user level for personal access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After running this command, Claude Code will have direct access to your Atlassian workspace,
including Confluence pages and Jira issues.&lt;/p&gt;

&lt;h2 id=&quot;real-world-use-case-opentelemetry-documentation&quot;&gt;Real-World Use Case: OpenTelemetry Documentation&lt;/h2&gt;

&lt;p&gt;Let me walk you through a practical example where I used Claude Code with the Atlassian MCP
integration to create comprehensive documentation for OpenTelemetry usage in a codebase.&lt;/p&gt;

&lt;h3 id=&quot;step-1-initial-setup-and-analysis&quot;&gt;Step 1: Initial Setup and Analysis&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2025/06/2025-06-27-claude-code-mcp-atlassian-001.png&quot; alt=&quot;Claude Code MCP Initial Setup&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The process begins by instructing Claude Code to analyze the codebase and understand how
OpenTelemetry is implemented. I started with this prompt:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Can you analyze this codebase and create a comprehensive Confluence page documenting how
OpenTelemetry is used throughout the project? Include code examples, configuration details, and best
practices.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Claude Code immediately began scanning the repository to understand:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;OpenTelemetry configuration files&lt;/li&gt;
  &lt;li&gt;Instrumentation patterns&lt;/li&gt;
  &lt;li&gt;Tracing implementations&lt;/li&gt;
  &lt;li&gt;Metrics collection setup&lt;/li&gt;
  &lt;li&gt;Custom spans and attributes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;step-2-documentation-generation-process&quot;&gt;Step 2: Documentation Generation Process&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2025/06/2025-06-27-claude-code-mcp-atlassian-002.png&quot; alt=&quot;Claude Code MCP Building Documentation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The AI systematically went through the codebase, identifying:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Configuration Analysis&lt;/strong&gt;: Examining &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;otel-config.yaml&lt;/code&gt;, environment variables, and
initialization code&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Instrumentation Patterns&lt;/strong&gt;: Finding auto-instrumentation setups and manual instrumentation&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Custom Implementations&lt;/strong&gt;: Discovering custom metrics, traces, and logging integrations&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Best Practices&lt;/strong&gt;: Identifying patterns that follow OpenTelemetry standards&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;step-3-content-creation-and-structuring&quot;&gt;Step 3: Content Creation and Structuring&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2025/06/2025-06-27-claude-code-mcp-atlassian-003.png&quot; alt=&quot;Claude Code MCP Generating Content&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Best Practice&lt;/strong&gt;: Before publishing directly to Confluence, I instructed Claude Code to
first generate the documentation as a local Markdown file. This approach offers several advantages:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Please create a comprehensive OpenTelemetry documentation as a Markdown file first.
I want to review and improve the content before publishing it to Confluence.&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This workflow allows you to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Review the generated content thoroughly&lt;/li&gt;
  &lt;li&gt;Make manual improvements and corrections&lt;/li&gt;
  &lt;li&gt;Add team-specific context and examples&lt;/li&gt;
  &lt;li&gt;Test code snippets and verify accuracy&lt;/li&gt;
  &lt;li&gt;Format the content properly before publication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Claude Code generated a well-structured local Markdown file including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Executive Summary&lt;/strong&gt;: High-level overview of OpenTelemetry usage&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Architecture Overview&lt;/strong&gt;: How observability fits into the system design&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Configuration Guide&lt;/strong&gt;: Step-by-step setup instructions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Code Examples&lt;/strong&gt;: Real examples from the codebase with explanations&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Troubleshooting Guide&lt;/strong&gt;: Common issues and solutions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Performance Considerations&lt;/strong&gt;: Best practices for production deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;step-4-review-improve-and-publish&quot;&gt;Step 4: Review, Improve, and Publish&lt;/h3&gt;

&lt;p&gt;After reviewing the local Markdown file, I made several improvements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Added company-specific configuration examples&lt;/li&gt;
  &lt;li&gt;Included troubleshooting steps for common issues encountered by the team&lt;/li&gt;
  &lt;li&gt;Updated code snippets to match the current codebase version&lt;/li&gt;
  &lt;li&gt;Added cross-references to relevant internal documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once satisfied with the content, I instructed Claude Code to publish the refined documentation to
Confluence:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;The Markdown documentation looks great! Please now create a Confluence page
with this content in the &apos;Engineering Documentation&apos; space.&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/software/2025/06/2025-06-27-claude-code-mcp-atlassian-004.png&quot; alt=&quot;Final Confluence Documentation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The final Confluence page was comprehensive and immediately useful for the development team. It
included:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Interactive code snippets with syntax highlighting&lt;/li&gt;
  &lt;li&gt;Diagrams showing trace flow&lt;/li&gt;
  &lt;li&gt;Configuration templates&lt;/li&gt;
  &lt;li&gt;Links to relevant Jira tickets&lt;/li&gt;
  &lt;li&gt;References to external OpenTelemetry documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;key-benefits-of-this-approach&quot;&gt;Key Benefits of This Approach&lt;/h2&gt;

&lt;h3 id=&quot;1-automated-code-analysis&quot;&gt;1. &lt;strong&gt;Automated Code Analysis&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Claude Code can understand complex codebases and extract meaningful patterns, saving hours of manual
documentation work.&lt;/p&gt;

&lt;h3 id=&quot;2-living-documentation&quot;&gt;2. &lt;strong&gt;Living Documentation&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Since the MCP integration allows direct updates to Confluence, documentation can be kept current
with code changes.&lt;/p&gt;

&lt;h3 id=&quot;3-consistent-structure&quot;&gt;3. &lt;strong&gt;Consistent Structure&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;AI-generated documentation follows consistent formatting and structure standards across all pages.&lt;/p&gt;

&lt;h3 id=&quot;4-cross-platform-integration&quot;&gt;4. &lt;strong&gt;Cross-Platform Integration&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;The Atlassian MCP server provides access to both Confluence and Jira, enabling rich
cross-referencing.&lt;/p&gt;

&lt;h2 id=&quot;best-practices-for-claude-code-mcp--atlassian&quot;&gt;Best Practices for Claude Code MCP + Atlassian&lt;/h2&gt;

&lt;h3 id=&quot;1-use-the-markdown-first-workflow&quot;&gt;1. &lt;strong&gt;Use the Markdown-First Workflow&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Always&lt;/strong&gt; request Markdown generation first: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;Create a Markdown file for this documentation&quot;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Review and improve the local file before publishing&lt;/li&gt;
  &lt;li&gt;Test all code examples and verify accuracy&lt;/li&gt;
  &lt;li&gt;Add team-specific context and examples&lt;/li&gt;
  &lt;li&gt;Use version control to track documentation changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;2-prepare-your-workspace&quot;&gt;2. &lt;strong&gt;Prepare Your Workspace&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Ensure you have appropriate permissions in Confluence&lt;/li&gt;
  &lt;li&gt;Create a dedicated space for AI-generated documentation&lt;/li&gt;
  &lt;li&gt;Set up page templates for consistency&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;3-provide-clear-instructions&quot;&gt;3. &lt;strong&gt;Provide Clear Instructions&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Be specific about the type of documentation needed&lt;/li&gt;
  &lt;li&gt;Include examples of desired output format&lt;/li&gt;
  &lt;li&gt;Specify which code patterns to focus on&lt;/li&gt;
  &lt;li&gt;Request Markdown format first, then Confluence publication&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;4-review-and-refine&quot;&gt;4. &lt;strong&gt;Review and Refine&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Always review AI-generated content before publishing&lt;/li&gt;
  &lt;li&gt;Add team-specific context that AI might miss&lt;/li&gt;
  &lt;li&gt;Update screenshots and diagrams as needed&lt;/li&gt;
  &lt;li&gt;Validate all code snippets and configurations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;5-maintain-security&quot;&gt;5. &lt;strong&gt;Maintain Security&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Be mindful of sensitive information in codebases&lt;/li&gt;
  &lt;li&gt;Review generated content for any exposed secrets&lt;/li&gt;
  &lt;li&gt;Use appropriate Confluence page restrictions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;advanced-use-cases&quot;&gt;Advanced Use Cases&lt;/h2&gt;

&lt;p&gt;The Claude Code MCP + Atlassian integration opens up many possibilities:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;API Documentation&lt;/strong&gt;: Generate comprehensive API docs from code comments and endpoints&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Architecture Decision Records&lt;/strong&gt;: Create ADRs based on code analysis and git history&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Onboarding Guides&lt;/strong&gt;: Build team onboarding documentation from project structure&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Security Reviews&lt;/strong&gt;: Document security implementations and compliance measures&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Performance Analysis&lt;/strong&gt;: Create performance optimization guides based on code patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The integration of Claude Code MCP with Atlassian represents a significant leap forward in automated
documentation generation. By combining AI’s analytical capabilities with Atlassian’s collaborative
platform, teams can maintain high-quality, up-to-date documentation with minimal manual effort.&lt;/p&gt;

&lt;p&gt;The OpenTelemetry documentation example demonstrates how this technology can transform a
time-consuming manual process into an automated workflow that produces professional-grade results.
As MCP continues to evolve, we can expect even more sophisticated integrations that will further
streamline development workflows.&lt;/p&gt;

&lt;p&gt;Try setting up the Claude Code MCP Atlassian integration in your environment and experiment with
documenting different aspects of your codebase. You might be surprised by how much insight AI can
provide into your own code!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Have you tried using Claude Code MCP with Atlassian? Share your experiences and use cases in the
comments below.&lt;/em&gt;&lt;/p&gt;
</description>
                <pubDate>Fri, 27 Jun 2025 09:00:00 +0000</pubDate>
                <link>https://ivandachev.com/blog/claude-code-mcp-atlassian-integration</link>
                <guid isPermaLink="true">https://ivandachev.com/blog/claude-code-mcp-atlassian-integration</guid>
                
                <category>software</category>
                
                
            </item>
        
            <item>
                <title>Parmesan Meatballs</title>
                <description>&lt;h1 id=&quot;dachevs-parmesan-meatballs&quot;&gt;Dachev’s Parmesan Meatballs&lt;/h1&gt;

&lt;p&gt;One of the most delicious meatball recipes I make. They turn out very juicy and aromatic thanks to
the parmesan.&lt;/p&gt;

&lt;h2 id=&quot;ingredients&quot;&gt;Ingredients&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;About 300-400g ground meat&lt;/strong&gt; - should be lean, pure meat without fat, in a 2:1 pork to beef
ratio&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;2 eggs&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Half a package of parmesan&lt;/strong&gt; - about 100-150g&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;2 slices of white bread&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pinch of salt&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Red pepper&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Optional - a pinch each of the following spices:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Black pepper&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Savory&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cumin&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Remove the crust from the bread slices and soak them thoroughly in water&lt;/li&gt;
  &lt;li&gt;Mix all ingredients very well until you get a uniform mixture&lt;/li&gt;
  &lt;li&gt;Shape the meatballs by hand&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;cooking&quot;&gt;Cooking&lt;/h2&gt;

&lt;p&gt;Cook in a pan without added fat. If the pan has a non-stick coating, you can cook directly. If it
doesn’t have such a coating, you can do a light searing with a little fat to prevent sticking.&lt;/p&gt;

&lt;p&gt;Cook on both sides until they become nicely golden.&lt;/p&gt;

&lt;h2 id=&quot;result&quot;&gt;Result&lt;/h2&gt;

&lt;p&gt;The meatballs turn out very tasty, juicy and aromatic. The parmesan gives them a special flavor that
makes them unforgettable.&lt;/p&gt;
</description>
                <pubDate>Thu, 05 Sep 2024 08:00:12 +0000</pubDate>
                <link>https://ivandachev.com/blog/parmesan-meatballs</link>
                <guid isPermaLink="true">https://ivandachev.com/blog/parmesan-meatballs</guid>
                
                <category>cooking</category>
                
                
            </item>
        
    </channel>
</rss>