feat: initial release of pengzhan.dev personal editorial blog platform

- Editorial web platform built with Node.js, Express, EJS, and Vanilla CSS
- Markdown content engine with YAML frontmatter, bilingual variants, and hot-reload watcher
- Unified SQLite with FTS5 search indexing, query logging, and schema filters
- Centered editorial post layout with margin-docked left TOC and mobile bottom sheet
- WordPress-grade comment system with moderation dashboard and bulk operations under /guanli
- Complete SEO suite (JSON-LD structured data, RSS/Atom feeds, XML sitemap, robots.txt)
- CI/CD workflows for linting, security audits (Gitleaks), automated tests, and Docker releases
This commit is contained in:
2026-09-16 23:08:53 -07:00
parent ac2c4c09ef
commit 8c0b04db0e
126 changed files with 8515 additions and 3984 deletions
+43
View File
@@ -0,0 +1,43 @@
site:
title: "Pengzhan"
tagline: "Was childish, Now foolish."
url: "https://pengzhan.dev"
author:
name: "Pengzhan Hao"
subtitle: "Software engineer on Cloud"
gravatar: "1f0283e19ce9680f2441b9c37211e0b890fd7ebf4b9ea5a5c413fe0379d7d3f9"
admin:
secret: "admin" # Admin dashboard password (or set via ADMIN_SECRET env var)
navigation:
- label: "Home"
path: "/"
- label: "Blogs"
path: "/blogs"
- label: "Search"
path: "/search"
- label: "Quick Links"
path: "/quick-links"
social:
- platform: github
url: "https://github.com/CoderSherlock"
- platform: instagram
url: "https://www.instagram.com/pengzhan.hao/"
- platform: linkedin
url: "https://www.linkedin.com/in/pengzhanhao/"
- platform: email
address: "[email protected]"
search:
recommended:
- label: 'tag:k8s "container image" category:tech'
query: 'tag:k8s "container image" category:tech'
plugins:
google-analytics:
enabled: true
tracking_id: "G-MNP4QN1T9T"
reading-time:
enabled: true
+2
View File
@@ -0,0 +1,2 @@
/* Custom CSS overrides on Persistent Volume */
/* Any CSS written here will be loaded after base and components CSS */
+104
View File
@@ -0,0 +1,104 @@
---
title: "Pengzhan Hao"
layout: home
permalink: "/"
---
<div class="home-hero-section">
<h1 class="hero-name">Pengzhan Hao</h1>
<p class="hero-subtitle">Software engineer on Cloud</p>
<div class="hero-intro">
<p>Joined Google in 2022, working in GKE, and focusing on Node &amp; runtime area. Most projects landed on bringing ARM-based VMs to GKE, introduced more flexibilities in node customization and pod lifecycle improvement for preemptible VMs</p>
<p>Contributed to Kubernetes open source community and became a member in 2023</p>
<p>Now working on making GKE a more productive platform for AI/ML</p>
</div>
</div>
<section class="home-section">
<h2 class="section-title">Research and study life in Binghamton University</h2>
<div class="two-column-grid">
<div class="column-block">
<p>Wide interests in multiple research areas, and spend most of my time in Edge computing, distributed systems and networks, and mobile operating system research. Under supervision from Professor Yifan Zhang, I spent 7 years in these research areas and outcome publications</p>
</div>
<div class="column-block">
<p>I worked as a teaching assistant for Operating system and Distributed system courses for both graduate and undergraduate levels. Mostly, I helped lecturers finish academic goals and hosted Labs for students. Before and during my research career, I finished my Master’s level education with a full grade point average.</p>
</div>
</div>
</section>
<section class="home-section">
<h2 class="section-title">Publications</h2>
<div class="publications-list">
<div class="pub-item">
<a href="/documents/eddl-sec21.pdf" target="_blank" class="pub-title">EDDL: A Distributed Deep Learning System for Resource-limited Edge Computing Environment</a>
<p class="pub-meta">Pengzhan Hao, and Yifan Zhang &bull; The Sixth ACM/IEEE Symposium on Edge Computing (ACM/IEEE SEC) &bull; San Jose, CA, USA, 2021.</p>
</div>
<div class="pub-item">
<a href="/documents/eta-infocom18.pdf" target="_blank" class="pub-title">A Case for Web Service Bandwidth Reduction on Mobile Devices with Edge-hosted Personal Services</a>
<p class="pub-meta">Yongshu Bai, Pengzhan Hao, and Yifan Zhang &bull; The 37th IEEE International Conference on Computer Communications (IEEE INFOCOM) &bull; Honolulu, HI, USA, 2018.</p>
</div>
<div class="pub-item">
<a href="/documents/a7-hao.pdf" target="_blank" class="pub-title">EdgeCourier: An Edge-hosted Personal Service for Low-bandwidth Document Synchronization in Mobile Cloud Storage Services</a>
<p class="pub-meta">Pengzhan Hao, Yongshu Bai, Xin Zhang, and Yifan Zhang &bull; The 2nd ACM/IEEE Symposium on Edge Computing (ACM/IEEE SEC) &bull; San Jose, CA, USA, 2017.</p>
</div>
<div class="pub-item">
<a href="/documents/p169-zhang.pdf" target="_blank" class="pub-title">Poster: Securing Device Inputs for Smartphones Using Hypervisor Based Approach</a>
<p class="pub-meta">Xin Zhang, Yongshu Bai, Pengzhan Hao, and Yifan Zhang &bull; The 15th ACM International Conference on Mobile Systems, Applications, and Services (ACM MobiSys) &bull; Niagara Falls, NY, USA, 2017.</p>
</div>
<div class="pub-item">
<a href="/documents/p163-hao.pdf" target="_blank" class="pub-title">Poster: EPS – Edge-hosted Personal Services for Mobile Users</a>
<p class="pub-meta">Pengzhan Hao, Yongshu Bai, Xin Zhang, and Yifan Zhang &bull; The 15th ACM International Conference on Mobile Systems, Applications, and Services (ACM MobiSys) &bull; Niagara Falls, NY, USA, 2017.</p>
</div>
</div>
</section>
<section class="home-section">
<h2 class="section-title">Undergraduate life in Beihang University</h2>
<div class="two-column-grid">
<div class="column-block">
<p>From 2011 to 2015, I attended the Software Engineering program at Beihang University. Overall, I received 3.25 out of 4 when graduating. During most of the era, I was enthusiasm in participating Movie Association and Mountain Climbing Association, and also worked as student assistant for career program for the last year.</p>
</div>
<div class="column-block">
<p>Starting from my junior year, I studied and researched consecutively in two labs. Worked in Android Kernel and module localization and smart urban computing areas. In urban computing areas, led a small team to participate in a joint project together by the Advanced Computer application technology engineering research center(Beihang University) and Microsoft Research Asia(MSRA).</p>
</div>
</div>
</section>
<section class="home-section">
<h2 class="section-title">Projects</h2>
<div class="projects-list">
<div class="project-item">
<h3 class="project-name">EDDL &ndash; Edge distributed deep learning framework</h3>
<p>A lite-weight c++ written framework(based on Dlib) for distributed neural network training on embedded devices and mobile phones. With supporting of our implemented runtime profilers, training devices can interconnect in an optimized network topology under various network environments. In our last publication, we showed our framework can perform distributed training for diverse neural networks on resource-limited devices. The EDDL framework also showed well scalability in large amounts of devices. We are currently working on network optimization on per-batch communication time and overall convergence time.</p>
</div>
<div class="project-item">
<h3 class="project-name">Edge Courier</h3>
<p>A proxy-based protocol for incremental file synchronization and cooperative online document editing. This protocol supports file hosting services including Google Drive, Dropbox, and OneDrive as well as document collaboration services such as G Suite and Microsoft 365. Edge courier can significantly decrease bandwidth consumption for collaborative editing web apps, and also showed advancement in cloud file storage services.</p>
</div>
<div class="project-item">
<h3 class="project-name">RTRouting assistant</h3>
<p>A real time routing prototype which can guide vehicle to alternative routes with high-volume traffic prediction. The predicted traffic alert is generated by a pre-trained model learned from history monitored traffics, real time event warnings and a abnormal traffic prediction model. This project belongs to a urban computing project studied together by Advance computer application technology engineering research center(Beihang University) and Microsoft Research Asia(MSRA).</p>
</div>
</div>
</section>
<section class="home-section">
<h2 class="section-title">Recognition</h2>
<div class="recognition-list">
<div class="recog-item">
<strong>ACM/IEEE SEC student travel grant</strong>
<span class="recog-meta">IEEE &bull; 2017, 2021</span>
</div>
<div class="recog-item">
<strong>ACM MobiSys 2017 student travel grant</strong>
<span class="recog-meta">ACM &bull; 2017</span>
</div>
</div>
</section>
+20
View File
@@ -0,0 +1,20 @@
---
title: "Quick Links"
permalink: "/quick-links"
---
A curated collection of public resources, contact points, and references:
## Professional Profiles
- **GitHub**: [github.com/CoderSherlock](https://github.com/CoderSherlock) &mdash; open-source projects, personal tools, and experiments.
- **LinkedIn**: [linkedin.com/in/pengzhanhao](https://www.linkedin.com/in/pengzhanhao/) &mdash; professional background.
- **Instagram**: [@pengzhan.hao](https://www.instagram.com/pengzhan.hao/) &mdash; photography and outdoor life.
## Direct Contact
- **Email**: [[email protected]](mailto:[email protected])
## Documents
- **Curriculum Vitae**: [Download CV (PDF)](/documents/CV.pdf)
@@ -0,0 +1,17 @@
module.exports = {
injectHead({ pluginConfig }) {
const trackingId = pluginConfig.tracking_id;
if (!trackingId) return '';
return `
<!-- Google Analytics (GA4 via Plugin) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=${trackingId}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${trackingId}');
</script>
`;
}
};
@@ -0,0 +1,5 @@
{
"name": "google-analytics",
"version": "1.0.0",
"description": "Injects Google Analytics 4 tracking script into head"
}
@@ -0,0 +1,18 @@
module.exports = {
onPostLoad({ post }) {
const wordCount = (post.rawContent || '').trim().split(/\s+/).length;
// Assume average 200 words per minute
const minutes = Math.max(1, Math.round(wordCount / 200));
post.readingTime = `${minutes} min read`;
post.wordCount = wordCount;
},
injectPostEnd({ post }) {
if (post && post.readingTime) {
return `<div style="font-family: var(--font-sans); font-size: 0.85rem; color: var(--color-text-muted); margin-top: 2rem; padding: 0.75rem 1rem; background: var(--color-surface-soft); border-radius: var(--radius-sm);">
Article statistics: ~${post.wordCount} words &bull; ${post.readingTime}
</div>`;
}
return '';
}
};
@@ -0,0 +1,5 @@
{
"name": "reading-time",
"version": "1.0.0",
"description": "Calculates reading time and word count for articles"
}
@@ -0,0 +1,15 @@
module.exports = {
onPostLoad({ post }) {
const raw = post.rawContent || '';
const internalMatches = raw.match(/\[[^\]]+\]\((\/[^)]+)\)/g) || [];
const externalMatches = raw.match(/\[[^\]]+\]\((https?:\/\/[^)]+)\)/g) || [];
post.seoMetrics = {
internalLinkCount: internalMatches.length,
externalLinkCount: externalMatches.length,
hasMetaDescription: Boolean(post.excerpt && post.excerpt.length > 30),
titleLength: post.title.length,
isTitleOptimal: post.title.length >= 25 && post.title.length <= 70
};
}
};
@@ -0,0 +1,5 @@
{
"name": "seo-analyzer",
"version": "1.0.0",
"description": "Dynamic SEO auditor and content health inspector"
}
@@ -0,0 +1,41 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="100%" height="100%">
<defs>
<linearGradient id="kidBg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fed7aa"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
<filter id="kidShadow" x="-10%" y="-10%" width="120%" height="120%">
<feDropShadow dx="0" dy="6" stdDeviation="10" flood-opacity="0.15"/>
</filter>
</defs>
<rect width="600" height="600" fill="url(#kidBg)" rx="32"/>
<!-- Creative Building Blocks / Robot Icon -->
<g transform="translate(300, 250)" filter="url(#kidShadow)">
<rect x="-90" y="-80" width="180" height="150" rx="24" fill="#ffffff"/>
<!-- Robot antenna -->
<line x1="0" y1="-80" x2="0" y2="-120" stroke="#ffffff" stroke-width="8" stroke-linecap="round"/>
<circle cx="0" cy="-125" r="14" fill="#ea580c"/>
<!-- Eyes -->
<circle cx="-40" cy="-15" r="16" fill="#0284c7"/>
<circle cx="40" cy="-15" r="16" fill="#0284c7"/>
<!-- Smile -->
<path d="M -40 30 Q 0 60 40 30" stroke="#ea580c" stroke-width="8" stroke-linecap="round" fill="none"/>
</g>
<!-- Educational Blocks -->
<g transform="translate(180, 420)" filter="url(#kidShadow)">
<rect x="0" y="0" width="60" height="60" rx="12" fill="#38bdf8"/>
<text x="30" y="42" text-anchor="middle" fill="#ffffff" font-family="-apple-system, sans-serif" font-size="32" font-weight="900">A</text>
</g>
<g transform="translate(260, 400)" filter="url(#kidShadow)">
<rect x="0" y="0" width="60" height="60" rx="12" fill="#ec4899"/>
<text x="30" y="42" text-anchor="middle" fill="#ffffff" font-family="-apple-system, sans-serif" font-size="32" font-weight="900">I</text>
</g>
<g transform="translate(340, 420)" filter="url(#kidShadow)">
<rect x="0" y="0" width="60" height="60" rx="12" fill="#10b981"/>
<text x="30" y="42" text-anchor="middle" fill="#ffffff" font-family="-apple-system, sans-serif" font-size="32" font-weight="900">&lt;&gt;</text>
</g>
<text x="300" y="530" text-anchor="middle" fill="#7c2d12" font-family="-apple-system, sans-serif" font-size="28" font-weight="800">Coding for Kids</text>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,26 @@
---
title: "AI可以改变什么:为孩子编程与创造力"
date: 2025-05-10
author: "haopengzhan"
category: "Non-tech"
tags: ["AI", "Parenting", "Education", "Kids"]
excerpt: "当AI能够直接生成代码,我们应该如何引导下一代理解技术、培养解决真实问题的创造力?"
cover: images/cover.svg
lang: zh
---
随着人工智能技术的迅猛普及,编程教育的门槛正在发生前所未有的变化。
过去,学习编程首先要克服繁琐的语法、编译器配置和环境搭建;而如今,孩子们只需要用自己的语言描述心中的想法,AI 就能协助将其变为可视化的交互程序。
## 从“写语法”到“定义问题”
在传统的教学中,很多孩子在记忆循环和变量类型时失去了兴趣。生成式 AI 带来的改变在于:
- **即时反馈**:孩子可以随时看到想法被渲染出来。
- **系统性思考**:重点转移为理解逻辑流程与规则边界。
- **激发创造力**:从消费者转变为创造者。
## 结语
技术工具永远在演进,不变的是面对未知问题时的探究欲望与审美能力。
@@ -0,0 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="100%" height="100%">
<defs>
<linearGradient id="kubeBg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#93c5fd"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<filter id="kubeShadow" x="-10%" y="-10%" width="120%" height="120%">
<feDropShadow dx="0" dy="8" stdDeviation="12" flood-opacity="0.25"/>
</filter>
</defs>
<rect width="600" height="600" fill="url(#kubeBg)" rx="32"/>
<!-- Kubernetes / Kubelet Hexagon -->
<g transform="translate(300, 260)" filter="url(#kubeShadow)">
<polygon points="0,-130 112,-65 112,65 0,130 -112,65 -112,-65" fill="#1e40af" stroke="#ffffff" stroke-width="8"/>
<!-- Central Ship Wheel / Helm Spokes -->
<circle cx="0" cy="0" r="45" fill="#3b82f6" stroke="#ffffff" stroke-width="6"/>
<circle cx="0" cy="0" r="18" fill="#ffffff"/>
<!-- Spokes -->
<line x1="0" y1="-75" x2="0" y2="75" stroke="#ffffff" stroke-width="6"/>
<line x1="-65" y1="-37" x2="65" y2="37" stroke="#ffffff" stroke-width="6"/>
<line x1="-65" y1="37" x2="65" y2="-37" stroke="#ffffff" stroke-width="6"/>
</g>
<!-- Large Kubelet Text -->
<text x="300" y="470" text-anchor="middle" fill="#ffffff" font-family="-apple-system, sans-serif" font-size="52" font-weight="900" letter-spacing="-1">Kubelet</text>
<text x="300" y="510" text-anchor="middle" fill="#dbeafe" font-family="-apple-system, sans-serif" font-size="20" font-weight="600" letter-spacing="2">RUNTIME &amp; PLEG DEEP DIVE</text>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,60 @@
---
title: "Kubelet Source Code Deep Dive: SyncLoop and PLEG"
date: 2025-07-15
author: "haopengzhan"
category: "Tech"
tags: ["k8s", "kubernetes", "go", "cloud", "containers"]
excerpt: "An in-depth exploration into the Kubernetes Kubelet runtime architecture, focusing on syncLoop mechanics and Pod Lifecycle Event Generator (PLEG)."
cover: images/cover.svg
lang: en
---
Kubelet is the primary "node agent" that runs on each Kubernetes worker node. It registers the node with the apiserver, watches for PodSpec changes, and ensures containers described in those PodSpecs are running and healthy[^1].
## Architectural Overview
At the heart of the Kubelet daemon is the `syncLoop`. The syncLoop monitors multiple channels for pod changes:
1. **Config channel**: Pods from API server, file manifests, or HTTP endpoints.
2. **PLEG channel**: Pod Lifecycle Event Generator events.
3. **Probe channel**: Liveness and readiness probe results.
4. **Housekeeping channel**: Periodic cleanup tasks.
### The SyncLoop Implementation
Here is a simplified view of how Kubelet receives events in Go:
```go
func (kl *Kubelet) syncLoop(updates <-chan kubetypes.PodUpdate, handler SyncHandler) {
klog.InfoS("Starting kubelet main sync loop")
for {
select {
case u, ok := <-updates:
if !ok {
klog.ErrorS(nil, "Updates channel closed")
return
}
handler.HandlePodAdditions(u.Pods)
case e := <-kl.pleg.Watch():
handler.HandlePLEGEvent(e)
}
}
}
```
## Pod Lifecycle Event Generator (PLEG)
PLEG periodically relists containers from the container runtime via CRI:
```bash
# Inspecting runtime events with crictl
crictl ps --state Running
```
If PLEG does not complete within the expected relist period (default 3 minutes), the node becomes `NotReady` with the condition `PLEG is not healthy`.
## Conclusion
Understanding the syncLoop provides clear insights into why nodes report PLEG issues during disk I/O bottlenecks or heavy container churn.
[^1]: Kubernetes documentation: https://kubernetes.io/docs/concepts/architecture/
@@ -0,0 +1,55 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="100%" height="100%">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#cbd5e1"/>
<stop offset="100%" stop-color="#94a3b8"/>
</linearGradient>
<filter id="shadow" x="-10%" y="-10%" width="120%" height="120%">
<feDropShadow dx="0" dy="8" stdDeviation="12" flood-opacity="0.18"/>
</filter>
</defs>
<rect width="600" height="600" fill="url(#bg)" rx="32"/>
<!-- Terminal Card -->
<g filter="url(#shadow)">
<rect x="70" y="140" width="280" height="200" rx="16" fill="#1e293b"/>
<!-- Terminal dots -->
<circle cx="95" cy="165" r="5" fill="#ef4444"/>
<circle cx="112" cy="165" r="5" fill="#f59e0b"/>
<circle cx="129" cy="165" r="5" fill="#10b981"/>
<!-- Terminal text -->
<text x="95" y="210" fill="#f8fafc" font-family="-apple-system, sans-serif" font-size="16" font-weight="700">Using Gemini-CLI</text>
<text x="95" y="235" fill="#93c5fd" font-family="-apple-system, sans-serif" font-size="14">and MCP Server</text>
<text x="95" y="260" fill="#cbd5e1" font-family="-apple-system, sans-serif" font-size="13">to Organize My</text>
<text x="95" y="285" fill="#38bdf8" font-family="-apple-system, sans-serif" font-size="15" font-weight="700">Dropbox</text>
</g>
<!-- Server Rack / MCP node -->
<g filter="url(#shadow)">
<rect x="400" y="130" width="130" height="220" rx="16" fill="#e2e8f0" stroke="#94a3b8" stroke-width="4"/>
<circle cx="465" cy="165" r="14" fill="#64748b"/>
<line x1="430" y1="210" x2="500" y2="210" stroke="#cbd5e1" stroke-width="4" stroke-linecap="round"/>
<line x1="430" y1="235" x2="500" y2="235" stroke="#cbd5e1" stroke-width="4" stroke-linecap="round"/>
<line x1="430" y1="260" x2="500" y2="260" stroke="#cbd5e1" stroke-width="4" stroke-linecap="round"/>
<line x1="430" y1="285" x2="500" y2="285" stroke="#cbd5e1" stroke-width="4" stroke-linecap="round"/>
</g>
<!-- Connecting Arrows -->
<path d="M 350 240 L 400 240" stroke="#0284c7" stroke-width="6" stroke-dasharray="6,4" stroke-linecap="round"/>
<path d="M 210 340 L 210 390 L 300 390 L 300 420" stroke="#0284c7" stroke-width="5" stroke-linecap="round"/>
<polygon points="300,435 292,418 308,418" fill="#0284c7"/>
<!-- Dropbox Box Icon -->
<g transform="translate(230, 440)" filter="url(#shadow)">
<!-- Top Left Diamond -->
<polygon points="70,10 35,32 70,55 105,32" fill="#0061ff"/>
<!-- Top Right Diamond -->
<polygon points="70,10 105,32 140,10 105,-12" fill="#3b82f6"/>
<!-- Bottom diamond front -->
<polygon points="70,55 35,78 70,100 105,78" fill="#1d4ed8"/>
<!-- Open flap left -->
<polygon points="35,32 0,55 35,78 70,55" fill="#2563eb"/>
<!-- Open flap right -->
<polygon points="105,32 70,55 105,78 140,55" fill="#1d4ed8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

@@ -0,0 +1,45 @@
---
title: "Using Gemini-CLI and MCP server to organize my dropbox"
date: 2025-08-31
author: "haopengzhan"
category: "Tech"
tags: ["AI Era", "Dropbox", "Gemini", "LLM", "Productivity", "k8s"]
excerpt: "I think many people face the same dilemma I did: Dropbox fills up with thousands of disorganized files. Here is how I leveraged Gemini-CLI and Model Context Protocol to automate organization."
cover: images/cover.svg
lang: en
---
I think many people face the same dilemma I did: years of accumulated receipts, research papers, camera uploads, and archives scattered across folders.
When managing workloads in modern infrastructure, we treat our nodes cleanly with a streamlined **container image** deployed across clusters. But our personal storage often looks like a monolithic legacy system.
## The Problem with Cloud Storage
Cloud storage services like Dropbox offer immense space, but search and organization remain rudimentary. You often remember *concepts* rather than filenames:
- "That invoice from AWS last quarter"
- "The PDF paper on distributed consensus"
- "A screenshot of my terminal settings"
## Introducing MCP (Model Context Protocol)
The Model Context Protocol connects LLMs with local or remote toolsets. By creating an MCP server for Dropbox, we expose simple tools:
```bash
# Running the MCP server locally or in a container
npx -y @modelcontextprotocol/server-dropbox
```
And in Python:
```python
import dropbox
def list_unorganized_files(dbx, path="/Inbox"):
res = dbx.files_list_folder(path)
return [entry.name for entry in res.entries]
```
## Results and Workflow
Once configured, Gemini can inspect file headers, categorize documents into appropriate directories, and even rename messy receipts into normalized ISO dates (`YYYY-MM-DD-merchant-amount.pdf`).
@@ -0,0 +1,27 @@
---
title: "使用 Gemini-CLI 与 MCP 服务整理 Dropbox"
date: 2025-08-31
author: "haopengzhan"
category: "Tech"
tags: ["AI Era", "Dropbox", "Gemini", "LLM", "Productivity", "k8s"]
excerpt: "面对堆积如山的 Dropbox 文件,如何使用大语言模型与 Model Context Protocol 构建自动化归档助手?"
cover: images/cover.svg
lang: zh
---
我想很多人都会遇到和我一样的困境:多年累积的单据、学术论文、照片杂乱无章地存放在 Dropbox 中。
在日常管理集群基础设施时,我们通过标准化的 **container image** 保持每个节点的干净与可复现。但我们的个人存储往往像一个臃肿的单体遗留系统。
## 云存储的管理困境
传统的文件夹分类需要大量人工维护,而且往往随着时间推移逐渐失控。借助 MCP 协议,我们可以让 AI 拥有读写文件的上下文能力。
```bash
# 启动 MCP 服务
npx -y @modelcontextprotocol/server-dropbox
```
## 总结与成效
现在每天晚上脚本自动运行,未分类文件自动按年月和类别归档,大幅提升了个人数字资产的管理效率。