---
title: "KubeWizard x LINE Bot Field Notes: Managing Kubernetes via Chat"
description: "A practical record of turning KubeWizard into a LINE Bot Agent API — manage Kubernetes from your phone via chat, with automation and pluggable tools, no laptop required."
canonical_url: "https://blog.markkulab.net/en/post/kubewizard-linebot-agent-api"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/en/author/mark-ku"
site: "Mark Ku's Tech Notes"
date_published: "2025-10-30 10:00:00 +0800"
category: "AI"
tags: ["kubewizard", "line bot", "kubernetes", "api", "devops", "chatbot", "python", "automation"]
language: "en"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "when reusing or quoting, credit the author and link back to the original"
---

# KubeWizard x LINE Bot Field Notes: Managing Kubernetes via Chat

## Preface

Managing Kubernetes used to mean `kubectl` or Dashboard — and when I'm out, that means VPN and remembering commands. A pain. This time I turned the open-source project KubeWizard into a LINE Bot Agent API: chat from your phone to query resources, view logs, restart services, plus automation and pluggable tools — a real upgrade for the ops experience.

Main features:
- Text-based K8s management (query resources / view Logs / restart)
- REST API event entry point (Prometheus / GitOps / Webhook)
- Pluggable tools — add AI helpers and automation scripts as needed
- Per-user isolated memory + smart context

I picked Google Gemini because:
- Has a Free Tier (enough for this)
- Integrates smoothly with Python / FastAPI / LangChain
- Good multilingual understanding — sufficient for ops scenarios

For Gemini API rate limits, see the official docs: [Gemini API Rate limits](https://ai.google.dev/gemini-api/docs/rate-limits)

![gemini rate limits](https://blog.markkulab.net/content/markku/posts/kubewizard-linebot-agent-api/images/gemini-quota.png)
---

## Why use LINE + Agent for K8s management?

### ✅ Anytime, anywhere
- No VPN, no terminal — your phone is enough
- Per-user sessions stay independent

### 🔗 Event-entry integration
- REST API can plug into Prometheus, GitLab, Argo CD, AlertManager Webhooks
- When alerts come in, the bot can reply on LINE with diagnostics and action options

### 🧠 Smart extensions
- Tools mode: K8s queries, Pipeline, Jira, log analysis, Search, HTTP calls to other APIs
- AI helps generate YAML, summarize errors, suggest fixes

### 🎯 Conversation memory
- Redis stores context + Token Buffer auto-summarizes
- Per-user routing — no cross-talk

---

## Architecture overview

End-to-end flow: user message → LINE → Webhook → Agent → Tools → reply

![System architecture diagram](https://blog.markkulab.net/content/markku/posts/kubewizard-linebot-agent-api/images/flowchart.png)

The architecture has four layers:

| Layer | Role | Description |
|------|------|------|
| Interface | LINE Bot / REST API | Multiple entry points, webhooks, alert/event injection |
| Intelligence | Agent + LLM | Decides whether to use tools, integrates output, maintains context |
| Tools | KubeTool / Search / RequestsGet / human-in-the-loop | Pluggable design, easy to extend, permission-isolated |
| State | Redis / Kubernetes SDK | Conversation memory, cluster operations, resource snapshots |

---

## Why use the Python Kubernetes SDK instead of calling kubectl directly?

| Aspect | Python SDK | Direct kubectl |
|------|------------|--------------|
| Security | Avoids string injection | Need careful command-string handling |
| Error handling | Structured exceptions | Hard to parse from text |
| Image size | Lightweight image | Need to install the CLI |
| Programmability | Object-based, easy to wrap | Need to parse output strings |
| RBAC integration | Native credentials/SA | Need to mount kubeconfig |

Auto-detect environment:
```python
def load_k8s_config():
    if os.path.exists("/var/run/secrets/kubernetes.io/serviceaccount/token"):
        config.load_incluster_config()
    else:
        config.load_kube_config()
```

Common mappings: `kubectl get pods -n X` → `v1.list_namespaced_pod(namespace=X)`.

---

## Step 1: Set up the LINE Bot (prerequisites)

1. Go to LINE Developers:  
   https://developers.line.biz/console/

2. Create a Provider

3. Create a Messaging API Bot

4. Get the Channel settings and write to `.env`:
```env
LINE_CHANNEL_SECRET=your_channel_secret
LINE_CHANNEL_ACCESS_TOKEN=your_access_token
```

5. Set the Webhook URL, e.g.:

```
https://your-domain.com/linebot/callback
```

![LINE Developers console basic settings for Egghead Bro bot channel](https://blog.markkulab.net/content/markku/posts/kubewizard-linebot-agent-api/images/linebot-console.png)
For Webhook testing, use ngrok to expose your local server.

### Recommended Webhook Settings

| Item | Value |
|-------|------------|
| Webhook URL | `https://example.com/linebot/callback` |
| Use webhook | ✅ Enabled |

> Must use HTTPS. Click Verify to confirm after success.

---

## Step 2: Core components for "LINE Bot Agent API"

By default, KubeWizard does single-turn Q&A. To make it a truly useful Agent, we add memory, tool selection, and multiple entry points.

### Core design

| Component | Function | Implementation |
|------|--------|----------|
| Agent | Analyzes messages and decides whether to use Tools | LangChain OpenAI Tools Agent |
| Tools | Provides functionality as plugins (K8s, Pipeline, AI, etc.) | LangChain BaseTool |
| Memory | Stores context and user state in Redis | RedisChatMessageHistory + ConversationTokenBufferMemory |
| API | Provides REST API and LINE Webhook | FastAPI |

### Modular features (Tools)

Each feature is a standalone Tool — extension is easy. Here's the KubeTool implementation:

```python
from langchain_core.tools import BaseTool
from kubernetes import client, config
from pydantic import BaseModel, Field

class KubeInput(BaseModel):
    """Parameter model for the Kubernetes tool"""
    commands: str = Field(
        ...,
        example="kubectl get pods",
        description="The kubectl-related command to execute"
    )

class KubeTool(BaseTool):
    """Kubernetes tool — executes K8s operations via the Python SDK"""
    
    name: str = "KubeTool"
    description: str = """Tool for running k8s-related commands on a Kubernetes cluster.
    Supports get/describe/logs/list operations.
    Special features:
    - Use 'kubectl list all' for a quick overview of all namespaces and pods
    - Use 'kubectl list namespaces' to list all namespaces
    - Use 'kubectl list pods' to view all pods grouped by namespace
    """
    args_schema: Type[BaseModel] = KubeInput
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # Auto-detect environment and load config
        try:
            config.load_incluster_config()  # In-Pod environment
            logger.info("Using in-cluster config (Pod environment)")
        except:
            config.load_kube_config()  # Local environment
            logger.info("Using local kubeconfig")
        
        self.v1 = client.CoreV1Api()
        self.apps_v1 = client.AppsV1Api()
    
    def _run(self, commands: str) -> str:
        """Execute kubectl command and return result"""
        # Parse the command and convert to SDK API calls
        # E.g., kubectl get pods -n default
        # Becomes: self.v1.list_namespaced_pod(namespace="default")
        ...
```

### Agent decision logic

```python
# Agent initialization
from langchain.agents import create_openai_tools_agent, AgentExecutor
from langchain_google_genai import ChatGoogleGenerativeAI

# Define available tools
tools = [
    KubeTool(),
    SearchTool(),
    RequestsGet(),
    human_console_input()
]

# Create the Agent
agent = create_openai_tools_agent(
    llm=ChatGoogleGenerativeAI(model="gemini-2.5-flash"),
    tools=tools,
    prompt=system_prompt
)

agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    memory=memory,
    verbose=True
)

# Flow: user question → Agent analyzes → picks tool → executes → returns result
result = agent_executor.invoke({"input": "list all pods"})
```

## My "Vibe Coding" iteration takeaways (real gotchas)

This time I didn't write a pile of design docs first — I built and adjusted in the rhythm I call "Vibe Coding," which roughly looks like this:

1. Get something running first: build a minimal `KubeAgent` with one `KubeTool`, where "list pods" works in the CLI is the first milestone.
2. Observe the model's "personality": does it hallucinate? Does it skip the tool when it should query? If yes, add a Prompt note: "analyze the question first, then decide whether to query."
3. Add one capability at a time: e.g., add `search`, then test 2-3 scenarios to confirm it actually uses it before adding `RequestsGet`, `human_console_input`.
4. Handle dangerous operations separately: I noticed delete / restart operations shouldn't be fully entrusted to the model, so I split out a `KubeToolWithApprove` requiring human confirmation.
5. Add memory only when conversations get long: don't rush Redis at first — wait until you genuinely feel "the bot forgets earlier turns," then plug in Redis + Token Buffer and watch token usage stabilize.
6. Optimize when real pain hits: e.g., when API gets slow or K8s is queried too often, then add "only fetch global state when keywords match." Don't pre-optimize for every imagined scenario.
7. Helm last: once standalone Docker / Compose is solid, package env vars, Secrets, and RBAC into a Helm Chart — turning it into a template you can drop into any cluster.

The core mindset is simple:

- Useful first, pretty later.
- Each iteration solves one real problem (e.g., memory mixing, replies too long, accidentally deleted resources).
- Use logs to see what the Agent is doing: skipping tools or using the wrong one usually means Prompt / tool descriptions need tuning.
- Use SDKs wherever possible — string-glue commands are a maintenance burden.

## Technical highlights, challenges, and solutions (plain language)

This section is "real gotchas I hit during implementation" — picking a few representative ones:

1. **Don't run `kubectl` directly — use the Python SDK**  
  - Problem: string-building `kubectl` invites shell injection, error messages are hard to handle, and the image needs an extra CLI.  
  - Solution: parse common commands like `kubectl get pods -n default` and map them to Python SDK calls like `v1.list_namespaced_pod(namespace="default")`, then format the output as a table.  
  - Benefit: controlled output, better security, easier to wrap as a Tool. Implemented in `tools/kubetool_sdk.py`.

2. **One codebase that runs both locally and inside K8s**  
  - Problem: locally you read `kubeconfig`, in-cluster you use ServiceAccount. Hardcoding either way means you forget the other.  
  - Solution: at startup, check whether the Pod's ServiceAccount token exists. If yes, `load_incluster_config()`; otherwise fall back to `load_kube_config()`.  
  - Benefit: same code for dev, test, and prod. Centralized in `utils/k8s_config.py`.

3. **Conversation memory grows; control Token cost**  
  - Problem: chat history balloons with use, slowing responses and inflating Token bills.  
  - Solution: store each user's conversation in Redis, use `ConversationTokenBufferMemory` to cap length, and have the model summarize older messages once a threshold is hit.  
  - Benefit: users still feel "memory" exists, but the backend isn't dragged down by the full history. Logic in `agents/kube_agent.py`.

4. **Multiple users — don't mix memories**  
  - Problem: if everyone writes to the same session, the Bot remembers wrong — A's last question gets B's context next.  
  - Solution: include `user_id` in the Redis key — each user gets an independent conversation space.  
  - Benefit: every user on LINE feels like they have their own assistant, no cross-talk. Also in `agents/kube_agent.py`.

5. **Dangerous operations need a "brake"**  
  - Problem: actions like deleting Pods or restarting Deployments are risky if the model decides to do them on its own.  
  - Solution: split tools into two — `KubeTool` (safe queries), and `KubeToolWithApprove` (requires human confirmation). Before any real change, ask first.  
  - Benefit: daily checks are smooth; cluster modifications still get human eyes. Implemented in `tools/kubetool_sdk.py`.

6. **Don't query the entire cluster for every question**  
  - Problem: querying every namespace/pod for every question is slow and wasteful.  
  - Solution: only attach a global snapshot when keywords like "list," "all," "what's there" appear; for follow-ups, only query things related to the previous question.  
  - Benefit: more stable response time, less stress on API / K8s. Logic in input pre-processing of `kube_agent.py`.

7. **Minimize RBAC permissions**  
  - Problem: cluster-admin is convenient but maximally risky.  
  - Solution: default to namespace-scoped Role; switch to ClusterRole only for cross-namespace needs. Both controlled via Helm `values.yaml`.  
  - Benefit: start safer, expand permissions only when needed. See `helm/values.yaml` and the RBAC section.

8. **Make replies "ops-friendly"**  
  - Problem: dumping raw output is hard to read on a phone.  
  - Solution: enforce output format in the Prompt — simple tables + key indicators. Make the most important information (which Pod failed, which Service has no backend) visible at a glance.  
  - Benefit: no more squinting at logs — straight to the next decision. Format hints live in the system prompt of `agents/kube_agent.py`.

None of these are deep "AI techniques" — they're more about gradually tuning a chatty Bot until it's actually useful in real ops.

## RBAC permission setup (recommended)

Below are the recommended minimum permissions, supporting both **Namespace Scoped** and **Cluster Wide** modes.

### Namespace Scoped (recommended, principle of least privilege)

**When to use:**
- You only need to manage resources in specific namespaces
- You don't need cluster-admin to deploy
- Safer, more aligned with enterprise security policies

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kubewizard-bot
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: kubewizard-bot-role
  namespace: default
rules:
  # Core resources
  - apiGroups: [""]
    resources: ["pods", "services", "endpoints", "events", "configmaps", "secrets", "persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  
  # Pod logs (read-only)
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get", "list"]
  
  # Apps resources
  - apiGroups: ["apps"]
    resources: ["deployments", "replicasets", "statefulsets", "daemonsets"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  
  # Batch resources
  - apiGroups: ["batch"]
    resources: ["jobs", "cronjobs"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  
  # Networking resources
  - apiGroups: ["networking.k8s.io"]
    resources: ["ingresses", "networkpolicies"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: kubewizard-bot-binding
  namespace: default
subjects:
  - kind: ServiceAccount
    name: kubewizard-bot
    namespace: default
roleRef:
  kind: Role
  name: kubewizard-bot-role
  apiGroup: rbac.authorization.k8s.io
```

### Cluster Wide (advanced)

**When to use:**
- Need to manage resources across namespaces
- Need to view cluster-level resources like nodes, namespaces
- Need cluster-admin to deploy

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kubewizard-bot
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kubewizard-bot-cluster-role
rules:
  # Namespace-scoped resources (all namespaces)
  - apiGroups: [""]
    resources: ["pods", "services", "endpoints", "events", "configmaps", "secrets", "persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get", "list"]
  
  - apiGroups: ["apps"]
    resources: ["deployments", "replicasets", "statefulsets", "daemonsets"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  
  - apiGroups: ["batch"]
    resources: ["jobs", "cronjobs"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  
  - apiGroups: ["networking.k8s.io"]
    resources: ["ingresses", "networkpolicies"]
    verbs: ["get", "list", "watch"]
  
  # Cluster-level resources (read-only)
  - apiGroups: [""]
    resources: ["nodes", "namespaces", "persistentvolumes"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubewizard-bot-cluster-binding
subjects:
  - kind: ServiceAccount
    name: kubewizard-bot
    namespace: default
roleRef:
  kind: ClusterRole
  name: kubewizard-bot-cluster-role
  apiGroup: rbac.authorization.k8s.io
```

### Helm Chart configuration (recommended)

The project includes a complete Helm Chart. Configure easily via `values.yaml`:

```yaml
# values.yaml

# RBAC config
rbac:
  # Whether to create RBAC resources
  create: true
  
  # Use Role (false) or ClusterRole (true)
  # Set false to avoid needing cluster-admin
  clusterWide: false
  
  # Custom RBAC rules
  rules:
    - apiGroups: [""]
      resources: ["pods", "services"]
      verbs: ["get", "list", "watch"]
```

**Deployment:**

```bash
# 1. Namespace-Scoped deployment (recommended)
helm install kubewizard ./helm \
  --set rbac.clusterWide=false \
  --set secrets.AI_GOOGLE_API_KEY="your-api-key" \
  --namespace default

# 2. Cluster-Wide deployment
helm install kubewizard ./helm \
  --set rbac.clusterWide=true \
  --set secrets.AI_GOOGLE_API_KEY="your-api-key" \
  --namespace default

# 3. Verify RBAC permissions
kubectl auth can-i list pods \
  --as=system:serviceaccount:default:kubewizard-bot \
  -n default
```

## Demo (text version)

### Example 1: Querying Pod status

**You:** Show me Pods in the default namespace  
**Bot:** 
```
📦 Namespace: default
================================
NAME                         READY   STATUS              RESTARTS   AGE
nginx-deployment-7d8f...     1/1     Running            0          2d
redis-master-0               1/1     Running            0          5d
payment-service-abc123       0/1     CrashLoopBackOff   5          10m

Total: 3 pods (2 Running, 0 Pending, 1 CrashLoopBackOff)
⚠️ Issue detected: payment-service-abc123 is in CrashLoopBackOff
Need to view Logs?
```

**You:** Show me the logs of that crashed one  
**Bot:** 
```
🔍 Recent logs for payment-service-abc123:

2025-11-22 10:30:15 [ERROR] Failed to connect to database
2025-11-22 10:30:15 [ERROR] Connection refused: mysql:3306
2025-11-22 10:30:15 [FATAL] Application startup failed

💡 Possible causes:
1. MySQL Service doesn't exist or isn't reachable
2. Misconfigured environment variable (DB_HOST)
3. Network policy blocking the connection

Suggested checks:
- kubectl get svc -n default | grep mysql
- Confirm Pod environment variable settings
```

**You:** Try restarting it  
**Bot:** 
```
🔄 Restarting Deployment: payment-service

✅ Executed: kubectl rollout restart deployment/payment-service -n default
⏳ Waiting for new Pods to start...

📊 Update status:
- Old Pods: terminating
- New Pods: creating
- ETA: ~30 seconds

I'll keep monitoring and report back.
```

### Example 2: Diagnosing network issues

**You:** Why is my Ingress unreachable?  
**Bot:** Let me diagnose your Ingress.

```
🔍 Diagnostic steps:

1️⃣ Check the Ingress resource
✅ Ingress 'my-app' exists
✅ Ingress Controller is running

2️⃣ Check the Service
✅ Service 'my-app-svc' exists (ClusterIP: 10.96.1.100)

3️⃣ Check the Pods
⚠️ Issue found: Service has no available backend Pods!

EndpointSlice info:
- my-app-svc: 0/3 endpoints ready

📋 Suggested fixes:
1. Check whether Deployment selector matches the Service
2. Check whether Pod labels are correct
3. Run: kubectl describe service my-app-svc -n default

Want me to run these checks for you?
```

### Example 3: Smart context memory

**You:** List all namespaces  
**Bot:** 
```
📋 All Namespaces:
1. default
2. kube-system
3. kube-public
4. production
5. staging
6. monitoring

Total: 6 namespaces
```

**You:** What's in production?  
**Bot:** *(intelligently remembers "production" namespace from previous turn)*
```
📦 Namespace: production
================================

Deployments:
- api-gateway (3/3 Ready)
- user-service (2/2 Ready)
- order-service (5/5 Ready)

Services:
- api-gateway-svc (LoadBalancer)
- user-service-svc (ClusterIP)
- order-service-svc (ClusterIP)

Total: 3 Deployments, 3 Services, 10 Pods (all healthy)
```

**You:** Restart api-gateway  
**Bot:** *(remembers we're talking about api-gateway in production namespace)*
```
Confirm restarting api-gateway in production namespace?
This will cause a brief service interruption.

[Confirmed]

🔄 Executing: kubectl rollout restart deployment/api-gateway -n production
✅ Restart succeeded! New Pods are running and ready.
```

![Real-world screenshot 1](https://blog.markkulab.net/content/markku/posts/kubewizard-linebot-agent-api/images/result-1.png)
![Real-world screenshot 2](https://blog.markkulab.net/content/markku/posts/kubewizard-linebot-agent-api/images/result-2.png)
---

## Closing

This article shows how to integrate KubeWizard with LINE Bot to build a chat-based K8s assistant. Key points:

### 📚 References

- [Quick Start Guide](https://github.com/markku636/kubewizard/blob/main/QUICKSTART.md)
- [LINE Bot Integration Docs](https://github.com/markku636/kubewizard/blob/main/kubewizard_linebot/LINE_BOT_README.md)
- [Kubernetes Configuration Guide](https://github.com/markku636/kubewizard/blob/main/docs/K8S_CONFIG_GUIDE.md)
- [Helm Chart Deployment Guide](https://github.com/markku636/kubewizard/blob/main/helm/DEPLOYMENT.md)

### Special thanks to the following open-source projects:
- [LangChain](https://python.langchain.com/) — Powerful LLM application framework
- [Google Gemini](https://ai.google.dev/) — Excellent AI model
- [Kubernetes Python Client](https://github.com/kubernetes-client/python) — Official Python SDK
- [FastAPI](https://fastapi.tiangolo.com/) — Modern web framework

---

## About this article and its author

Originally published on [Mark Ku's Tech Notes](https://blog.markkulab.net/en/post/kubewizard-linebot-agent-api)

License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — when reusing or quoting, credit the author and link back to the original

### About the author

**[Mark Ku](https://blog.markkulab.net/en/author/mark-ku)** — Software Solution Provider

- 10+ years senior software engineer, now an AI Builder
- Focused on large-platform architecture — North-American e-commerce, AI SaaS subscription billing
- Combining AI Agents and automation to build evolvable product foundations

### Free tools built by the author

All of these are free to use:

- [Free PDF Sign Tool](https://blog.markkulab.net/en/tools/pdf-sign): Online PDF sign tool — draw, type, or upload a signature, then drag, resize, and download. Everything runs in your browser; nothing is uploaded.
- [VS Code Refactory](https://blog.markkulab.net/en/tools/refactory): Refactory is a VS Code refactoring extension: 34 actions plus a 37-rule code-smell inspection layer with a Code Health dashboard, across 18 languages, backed by 534 tests. It learns your repo's conventions: where interfaces live, where DI is registered, whether 'use client' belongs. It ranks files by git churn × complexity so you know what to fix first, and hands any smell to the Claude Code already on your machine. Free to use, and your source never leaves your computer.
- [DB-Kit Database Manager](https://blog.markkulab.net/en/tools/db-kit): DB-Kit is a lightweight, cross-platform database manager built with Tauri + Rust + React. Manage MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, SQLite, MongoDB, Redis, Kafka, Elasticsearch and RabbitMQ from one consistent interface: passwords encrypted in the OS keychain, SSH tunnels, full CRUD, a visual query builder, stacked multi-statement result sets, cross-connection data transfer and compare/sync, Excel / CSV import & export, visualized execution plans, ER diagrams, scheduled backups, SQL stress testing with p50–p99 latency percentiles, a 15-rule SQL review engine, Kafka message browsing with monitoring & alerts, a bilingual UI (Traditional Chinese / English), a built-in AI assistant (natural-language SQL, AI review and tuning advice) and the dbk CLI. Free and open source (MIT), with installers for Windows, macOS and Linux.
- [VS Code Super Mermaid](https://blog.markkulab.net/en/tools/super-mermaid): Super Mermaid is a VS Code extension for beautiful Mermaid diagrams out of the box: auto-colored live preview, mouse pan & zoom, high-res PNG / SVG export, 21 templates and multiple themes. Free and open source (MIT).
- [React Super Mermaid](https://blog.markkulab.net/en/tools/react-super-mermaid): react-super-mermaid is an open-source React component library: render beautiful Mermaid diagrams with a single <MermaidViewer>, with built-in colorful / sketch themes, pan & zoom, in-diagram search, and high-res SVG / PNG export. Lightweight, SSR-safe, fully typed. Free and open source (MIT).
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/en/tools/jira-super-mermaid): An Atlassian Forge app: write Mermaid syntax directly inside a Jira issue or a Confluence page and get flowcharts, sequence diagrams, state machines and Gantt charts. 11 diagram types, SVG / PNG export, light and dark themes, full CJK support. Runs on Atlassian: your diagrams live in your own site and the app calls no third-party service. Free, coming soon to the Atlassian Marketplace.
- [Mermaid Live Preview](https://blog.markkulab.net/en/tools/mermaid-preview): Write Mermaid in your browser, see it render instantly, and share the whole diagram as a single link. No sign-up, nothing uploaded to a server, and mermaid.live share links work as-is.
- [React Intl Phone Number](https://blog.markkulab.net/en/tools/react-intl-phone-number): react-intl-phone-number is an open-source React component: framework-agnostic and antd-free, with E.164 in/out, a searchable flag / country-code dropdown, configurable validation levels (strict / mobile-strict / loose), themeable CSS, and i18n — phone logic powered by google-libphonenumber. Lightweight and fully typed. Free and open source (MIT).
- [Uptime Kuma Cluster](https://blog.markkulab.net/en/tools/uptime-kuma-cluster): Turn single-node Uptime Kuma into a highly available cluster: OpenResty + Lua smart load balancing, shared MariaDB state, health checks and automatic failover, plus cluster-management REST APIs. One Docker Compose command to start. Free and open source (MIT).
- [Special Education](https://blog.markkulab.net/en/education): Learning materials crafted for special education students

### Daily podcasts

- [Mark's Tech Insights — Daily AI News](https://blog.markkulab.net/en/category/tech-news): Daily curated AI and tech trends. Catch the latest developments via audio summaries — covering AI applications, software architecture, DevOps, and engineering practice. — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/en/category/ai-stock-chat): Every trading day, an AI-analyzed take on the Taiwan stock market, delivered as a two-host conversation covering the session and the next-day outlook. — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml
- [開源好物週報](https://blog.markkulab.net/en/category/open-source-weekly): A weekly two-host pick of free open-source tools surfaced from real Hacker News, GitHub, and Reddit buzz — what pain they solve and the fastest way to get started. — RSS: https://blog.markkulab.net/open-source-weekly/feed.xml

### Newsletter

[Subscribe to the newsletter](https://blog.markkulab.net/en/subscribe) — Be the first to know about new posts. No spam, unsubscribe anytime.
