AI NEVER LATE.

PRACTICAL WORKSHOP / 10 CHAPTERS

由一份清單,建立
AI Agent Project Board

由 Project Data、Astro、GitHub、Cloudflare,一路做到 AI Agent 可以替你更新 Project Status。

這份教學會帶你由零開始建立一個 Project Control Board。你不需要先識寫完整網站,但需要願意跟步驟建立資料檔、執行少量 Terminal 指令,以及設定 GitHub 和 Cloudflare。

今次實驗使用 Hermes 作 AI Agent,但 Hermes 並非必要。任何可以讀寫檔案、執行 Terminal、使用 Git、修改程式碼、執行 build / test 的 AI Agent,都可以採用同一套架構。

← 返回 Project Page

AFTER THE WORKSHOP

完成後你會得到

C1

CHAPTER 01 / 10

準備環境

01 這一章會做到甚麼

確認電腦可以執行 Node.js、npm 和 Git,並準備 GitHub、Cloudflare 帳戶及一個可操作檔案和 Terminal 的 AI Agent。

02 為甚麼要做

先檢查工具,之後遇到錯誤才知道是程式問題,還是電腦未裝好。你不需要是 Programmer,但要識得開 Terminal、進入資料夾及複製指令。

03 Step-by-step

  1. 選一部 Mac、Windows 或 Linux 電腦,先安裝目前仍受支援的 Node.js LTS。可以用 Node.js 官方 installer,或你熟悉的 package manager;安裝途中保留 npm。
  2. 如果 Git 未安裝,使用作業系統官方安裝方法。Windows 用戶可安裝 Git for Windows,之後用 Git Bash 或 PowerShell。
  3. 建立 GitHub 和 Cloudflare 帳戶,建議開啟 multi-factor authentication;今次先不用建立任何 API key。
  4. 準備一個可以讀寫指定 project folder、執行 Terminal、使用 Git、跑 build/test 的 AI Agent。Hermes 是今次示範工具,不是唯一選擇。
  5. 開一個新的 Terminal 視窗,執行右邊的版本檢查。

04 Copy / Command

Mac / Linux / Windows PowerShell
node -v
npm -v
git --version

05 完成後應該見到甚麼

  • 三個指令都回傳版本號,例如 Node 的 vXX、npm 的版本號及 git version XX。
  • Node.js installer 裝好後,關閉再重新開 Terminal,避免舊視窗未讀到 PATH 更新。
07 下一章

環境準備好後,先整理資料欄位;暫時不要急住畫 Dashboard。

前往 C2 →
C2

CHAPTER 02 / 10

建立 Project Data

01 這一章會做到甚麼

建立一份 `src/data/projects.yaml`,用它保存每個 Project 的資料,作為唯一的 source of truth。

02 為甚麼要做

資料和網頁分開,Agent 才能只更新資料,Dashboard 再按同一格式呈現。先整理欄位亦會減少之後改網頁的次數。

03 Step-by-step

  1. 先列出你真正會用到的欄位:id、name、tier、status、priority、next_action、last_updated。
  2. 建立 `src/data` 資料夾,再新增 `projects.yaml`。每個 Project 要有唯一 id;tier 用 1、2 或 3;status 固定用 ACTIVE、WAITING、PAUSED、COMPLETED 或 ARCHIVED;未知值用 null,不要靠估。
  3. 先用一至三個不敏感的測試 Project 練習,核對 YAML 的縮排必須使用空格,不能混入 Tab。
  4. 想清楚哪些內容可以公開。`visibility: public` 只是資料標籤,不會替網站加密;靜態網站打包的資料都可以被訪客讀取。

04 Copy / Command

src/data/projects.yaml
projects:
  - id: p001
    name: Website Redesign
    program: Personal
    tier: 1
    status: ACTIVE
    priority: HIGH
    progress: null
    next_action: Finish homepage layout
    waiting_for: null
    last_updated: 2026-10-07
    notes: null
    links: []
    visibility: public

05 完成後應該見到甚麼

  • 檔案位置是 `src/data/projects.yaml`,第一層有 `projects:`,每個 `-` 是一個 Project。
  • 同一份資料不會在多個頁面各自複製;status、tier 和日期的寫法保持一致。
07 下一章

資料格式穩定後,建立 Astro 專案並在 build 時讀取 YAML。

前往 C3 →
C3

CHAPTER 03 / 10

建立 Astro Dashboard

01 這一章會做到甚麼

由 Astro 建立一個 static 網站,在 build 時讀取 YAML,並把 Project 名稱、tier 和下一步顯示成 HTML。

02 為甚麼要做

對個人、低頻更新的 Board,SSG / static site 通常比常駐 server 簡單;資料改變時重新 build 就可以更新頁面。

03 Step-by-step

  1. 在 Terminal 先切換到你準備放 project 的位置,照指令建立 Astro minimal 專案。
  2. 安裝 `yaml` 套件,建立 `src/data/projects.yaml`,把 C2 的測試資料放進去。
  3. 在 `src/pages/index.astro` 用 `yaml` 套件讀取 YAML;先只顯示 Project 名稱和 next_action,確認資料能被讀到。
  4. 把第三段的 `tests/data.test.mjs` 範例存到 `tests/data.test.mjs`;`npm pkg set` 已在 command 區加入 Node test runner。
  5. 執行 `npm test` 和 `npm run build`,兩個都通過後才繼續。
  6. 啟動本機 dev server,照 Terminal 顯示的 local URL 用瀏覽器檢查;完成後按 Terminal 的 Ctrl+C 停止 server。

04 Copy / Command

建立專案及安裝 YAML / test runner
npm create astro@latest project-control -- --template minimal
cd project-control
npm install
npm install yaml
npm pkg set "scripts.test=node --test"
src/pages/index.astro 的最小資料讀取範例
---
import { parse } from "yaml";
import yamlText from "../data/projects.yaml?raw";
const { projects = [] } = parse(yamlText);
---
<html lang="zh-HK">
  <head><meta charset="utf-8" /><title>Project Control</title></head>
  <body>
    <main>
      <h1>Project Control</h1>
      {projects.map((project) => (
        <article>
          <h2>{project.name}</h2>
          <p>Tier {project.tier} · {project.status}</p>
          <p>下一步:{project.next_action ?? "待補充"}</p>
        </article>
      ))}
    </main>
  </body>
</html>
tests/data.test.mjs:檢查 YAML 有資料、id 唯一和 tier/status 合法
import test from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { parse } from "yaml";

const text = await readFile(new URL("../src/data/projects.yaml", import.meta.url), "utf8");
const { projects = [] } = parse(text);

test("Project records have unique ids and valid tiers/statuses", () => {
  assert.ok(projects.length > 0);
  assert.equal(new Set(projects.map((project) => project.id)).size, projects.length);
  for (const project of projects) {
    assert.ok([1, 2, 3].includes(project.tier));
    assert.ok(["ACTIVE", "WAITING", "PAUSED", "COMPLETED", "ARCHIVED"].includes(project.status));
  }
});
全部檔案建立後才執行:test、build、本機預覽
npm test
npm run build
npm run dev

05 完成後應該見到甚麼

  • `npm test` 顯示 data test 通過,`npm run build` 成功;最後 `npm run dev` 啟動後,瀏覽器見到 Project Control 和 YAML 中的測試 Project。
  • 改 YAML 的 name 後重新整理頁面,顯示內容跟住改變;這表示網頁真的是讀取 source of truth。
07 下一章

讀得到資料後,把單張文字列表整理成容易在手機瀏覽的 Project Card 和篩選器。

前往 C4 →
C4

CHAPTER 04 / 10

加入 Project Card 和篩選

01 這一章會做到甚麼

把每個 Project 顯示成一張卡,清楚列出 tier、status、priority 和 next_action,並用 Tier filter 快速縮小列表。

02 為甚麼要做

Dashboard 的目的不是展示程式碼,而是打開就知道先做甚麼;狀態和下一步要比裝飾更易讀。

03 Step-by-step

  1. 沿用 C3 讀到的 `projects` 陣列,不要在 Astro 檔案另外寫第二份 Project 資料。
  2. 每張卡放 Project 名稱、tier、status 和 next_action;沒有 next_action 時顯示「待補充」,不要留一塊空白。
  3. 先用一個 Tier 下拉選單做 filter。確認一、二、三梯隊可以切換,再視乎需要加 status filter。
  4. 用窄視窗測試:卡片改為一欄,文字不被截斷,按鈕可用手指點到。

04 Copy / Command

卡片及 Tier filter(放在 Astro 頁面的 HTML 區段)
<label for="tier-filter">顯示梯隊</label>
<select id="tier-filter">
  <option value="all">全部</option>
  <option value="1">Tier 1</option>
  <option value="2">Tier 2</option>
  <option value="3">Tier 3</option>
</select>
<div class="project-grid">
  {projects.map((project) => (
    <article data-project-card data-tier={project.tier}>
      <p>Tier {project.tier} · {project.status}</p>
      <h2>{project.name}</h2>
      <p>下一步:{project.next_action ?? "待補充"}</p>
    </article>
  ))}
</div>
<script>
  const filter = document.querySelector("#tier-filter");
  if (filter) {
    filter.addEventListener("change", () => {
      document.querySelectorAll("[data-project-card]").forEach((card) => {
        card.hidden = filter.value !== "all" && card.dataset.tier !== filter.value;
      });
    });
  }
</script>
加到同一個 Astro 檔案的 mobile-first CSS
.project-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}

[data-project-card] {
  padding: 16px;
  border: 1px solid #29343b;
  border-radius: 8px;
}

@media (min-width: 700px) {
  .project-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
PUBLIC DEMO DATA dashboard:五個安全示範 Project 的卡片與 Tier 分組。
PUBLIC DEMO DATA:以安全示範資料展示 Project 卡片、Tier、Status 和 Next Action;不是 Live Demo。

05 完成後應該見到甚麼

  • 選 Tier 1 時只見到 Tier 1 卡片;選「全部」會還原所有卡片。
  • 桌面可以兩欄,窄螢幕改一欄;重要資料不需要左右捲動才看得到。
07 下一章

本機畫面可用後,先整理 `.gitignore`,再用 Git 留下可回復的版本。

前往 C5 →
C5

CHAPTER 05 / 10

建立 GitHub Private Repo

01 這一章會做到甚麼

在 GitHub 建一個 private repository,保存程式碼和版本歷史;Cloudflare 連接它之後可以自動部署。

02 為甚麼要做

Git 可以比較每次修改、回復壞版本;Private repo 限制原始碼存取,但不會自動保護部署後的網頁內容。

03 Step-by-step

  1. 在 GitHub 建立新 repository,選 Private;如本機已有 Astro 專案,不要再初始化另一份 README,以免兩邊第一個 commit 不同。
  2. 先在 project 根目錄建立 `.gitignore`,排除 node_modules、dist、本機 `.env`、credential 檔案。
  3. 在 commit 前執行 `git status --short`,逐項檢查準備加入的檔案;不要把 API key、password、token 或私人 export 放入 repo。
  4. 如果資料夾已有 Git,就用 `git switch -c staging` 建新 branch,不要再跑 init;新資料夾可用 staging 作第一個 branch。舊版 Git 不認得 `git init -b` 時,先 `git init` 再 `git switch -c staging`。已有 repository 的讀者先不要推 production branch。Authentication 和第一次 push 留到下一章。

04 Copy / Command

.gitignore(在 project 根目錄)
node_modules/
dist/
.env
.env.*
!.env.example
.DS_Store
新資料夾建立 staging commit(已有 Git repo 先略過 git init)
git init -b staging
git status --short
git add .
git status --short
git commit -m "Create project control dashboard"
git remote add origin https://github.com/<YOUR_ACCOUNT>/<YOUR_PRIVATE_REPO>.git

05 完成後應該見到甚麼

  • GitHub repository 的 Visibility 是 Private;本機 `git status` 顯示的只有你預期納入的檔案。
  • 本機有一個 staging branch 和 commit;remote 尚未 push 時,GitHub 網頁可能仍看不到 commit。
07 下一章

Repo 和本機 commit 準備好後,用安全的登入流程授權 Git,不要把 token 貼進 prompt。

前往 C6 →
C6

CHAPTER 06 / 10

設定 GitHub Authentication

01 這一章會做到甚麼

讓本機 Git 能安全地讀寫自己的 repository,並確認 staging push 確實到達 GitHub。

02 為甚麼要做

GitHub 密碼或 token 不應出現在程式碼、截圖、Terminal history 或 AI 對話;用官方授權工具可以避免手動抄 secret。

03 Step-by-step

  1. 如果沒有 `gh`,先按 GitHub CLI 官方安裝說明安裝,然後重新開 Terminal。
  2. 執行 `gh auth login`,選 GitHub.com 和 HTTPS,跟住官方 browser flow 完成授權;不要複製 token 給 Agent。
  3. 用 `gh auth status` 檢查登入狀態,再確認 remote 指向自己的 private repo。
  4. 第一次推送只推 staging branch。用 `git ls-remote` 從遠端讀回 branch SHA,確認和本機 commit 一致。

04 Copy / Command

Browser-based login 及 staging push
gh auth login
gh auth status
git remote -v
git push -u origin staging
git ls-remote origin refs/heads/staging

05 完成後應該見到甚麼

  • `gh auth status` 顯示已登入 GitHub;不要截圖或分享任何 token 值。
  • `git ls-remote` 回傳 staging branch 和 commit SHA;SHA 應對應本機 `git rev-parse HEAD`。
07 下一章

GitHub 有 staging commit 後,再由 Cloudflare Pages 連接 staging branch 做 preview deployment。

前往 C7 →
C7

CHAPTER 07 / 10

部署 Cloudflare Pages

01 這一章會做到甚麼

連接 GitHub repository,指定 staging branch、build command 和 Astro 輸出資料夾,取得一個測試用 preview。

02 為甚麼要做

Git push 後自動 build,能讓你在合併或切換正式環境之前,先從瀏覽器檢查成品。

03 Step-by-step

  1. 登入 Cloudflare Dashboard,進入 Workers & Pages,建立 Pages project 並選 Connect to Git。
  2. 授權 Cloudflare 讀取你選擇的 GitHub private repository;只授權必要 repo。
  3. Framework 選 Astro;Build command 設 `npm run build`,Build output directory 設 `dist`,production branch 按你的部署政策設定。
  4. 先部署沒有私人資料的 staging branch。等部署狀態顯示成功,再從 Cloudflare deployment record 開啟它提供的 preview URL。
  5. 如果 Dashboard 有私人資料,先不要把它放在 public Pages。GitHub private repo 不會令網站 private;只有先設定並實測 Cloudflare Access 覆蓋所有頁面、圖片和 preview hostname,才可以放 private data。無法確認時只用假資料或留在本機。

04 Copy / Command

Astro Pages build 設定
Framework preset: Astro
Build command: npm run build
Build output directory: dist
Preview branch: staging

05 完成後應該見到甚麼

  • Cloudflare deployment 頁面顯示 Build successful,並列出 commit 和 provider-generated preview link。
  • 開啟 preview 後確認標題、圖片、mobile layout 和連結;此網址只當 staging 使用,不放入公開教材或截圖。
07 下一章

部署流程清楚後,寫好 Agent 的操作界線,先讓它做可審核的更新。

前往 C8 →
C8

CHAPTER 08 / 10

設計 AI Agent Workflow

01 這一章會做到甚麼

讓 Agent 讀 Project Data、只改獲授權的欄位、跑 test/build、檢查 diff,再由人決定是否 commit 和 deploy。

02 為甚麼要做

Agent 擅長重複操作;Project 優先次序、模糊進度和是否完成,仍應由人作決定。

03 Step-by-step

  1. 在 repo 的 README 寫明 data schema、允許的 status、不要修改的檔案及測試指令。
  2. 每次任務先要求 Agent 檢查現況和列出不確定欄位;資訊不足就問,不要推斷 next_action 或完成率。
  3. 只批准需要的檔案變更;Agent 完成後跑 test、build、diff check,逐項讀 diff。
  4. Push staging 前先確認 branch;production push、merge、刪除歷史都要有明確的人手批准。

04 Copy / Command

可貼給 Hermes 或其他 Agent 的安全工作提示
請先閱讀 README、schema 和目前的 projects.yaml。
只更新我明確指定的 Project 和欄位;不確定的資料請先問,不要猜。
不要輸出、複製或要求任何 password、token、API key 或 credential。
不要修改 homepage、production branch 或私人部署設定。
完成後執行 npm test、npm run build、git diff --check,
列出改動檔案和 diff;未經我確認,不要 push 或 deploy。
每次更新後的驗收指令
npm test
npm run build
git diff --check
git status --short
git diff -- src/data/projects.yaml

05 完成後應該見到甚麼

  • Agent 會先報告疑問,再只修改指定 YAML;不會憑空補進度或把 credential 貼入檔案。
  • Test、build 和 diff 都可供人檢查;你可以先人工批准,再自行 commit/push。
07 下一章

人工更新穩定後,再考慮每天保存 snapshot 和產生 Morning Brief。

前往 C9 →
C9

CHAPTER 09 / 10

Nightly Update 和 Morning Brief

01 這一章會做到甚麼

先以 dry-run 建議更新,保存有日期的 snapshot,再整理一份標示資料時間的 Morning Brief。

02 為甚麼要做

有 snapshot 才能回顧 Project 狀態如何變化;dry-run 和 review 則避免錯誤自動改寫或推送。

03 Step-by-step

  1. 先手動跑一次 dry-run:Agent 列出狀態變更候選,不直接覆寫 status 或 push。
  2. 確認來源、時區、快照檔名與保存期限;每天一份,例如 `snapshots/projects-YYYY-MM-DD.yaml`,同一天重跑不要靜默覆蓋。
  3. 在 Agent 的 scheduled-task / scheduler 設定建立 `Nightly Project Review`:選本地時區和每日 21:00,把 dry-run prompt 貼入並設定失敗通知;先連續 dry-run 一週。若 scheduler 在個人電腦上,睡眠或關機時任務可能不會執行。
  4. Morning Brief 只摘要 Tier 1、到期項目、等待回覆和最近變更;每項標明資料時間,不要把舊 snapshot 說成即時狀態。
  5. 先產生 draft 讓人 review;穩定後再逐項授權自動 snapshot。不要一開始就授權自動改 status、push 或部署。

04 Copy / Command

Mac / Linux / Git Bash:手動保存日期 snapshot(存在就拒絕覆寫)
mkdir -p snapshots
target="snapshots/projects-$(date +%F).yaml"
test ! -e "$target" || { echo "Snapshot exists; refusing overwrite"; exit 1; }
cp src/data/projects.yaml "$target"
git status --short
Windows PowerShell:手動保存日期 snapshot(存在就拒絕覆寫)
New-Item -ItemType Directory -Force snapshots | Out-Null
$day = Get-Date -Format yyyy-MM-dd
$target = "snapshots/projects-$day.yaml"
if (Test-Path $target) { throw "Snapshot exists; refusing to overwrite" }
Copy-Item src/data/projects.yaml $target
git status --short
Nightly Update dry-run prompt
每晚執行一次 dry-run:讀取目前 projects.yaml 和上一份已確認 snapshot。
只根據我明確授權的來源提出候選更新;資料不確定就標示「未確認」,不要自行改 status/progress。
如 reports/ 資料夾不存在,先建立;把候選項目和來源寫入 reports/nightly-draft.md。不得修改 projects.yaml、push、寄信或部署。
如已有同日 draft,先保留舊檔並用不同檔名;完成後回報來源時間、差異和錯誤。
Morning Brief draft prompt
根據最新已驗證的 projects.yaml 和 snapshot,產生今日 Morning Brief 草稿。
先列 Tier 1,再列等待事項和最近狀態變化;每項附上 Project id。
標示資料最後更新時間;未知值寫「未確認」,不要推斷。
不要修改資料、寄信、push 或部署,只輸出供我 review 的草稿。

05 完成後應該見到甚麼

  • snapshot 檔名包含日期,內容可從 Git diff 看出和上一日的差異。
  • Morning Brief 顯示來源和更新時間;沒有資料時清楚顯示「未確認」。
07 下一章

最後比較 Static 與 SSR,確認目前架構夠用時就先不要增加維護負擔。

前往 C10 →
C10

CHAPTER 10 / 10

SSG vs SSR:幾時需要升級?

01 這一章會做到甚麼

分清 SSG / static 和 SSR / dynamic app 的資料流程,按使用人數、登入、更新頻率和資料庫需求作選擇。

02 為甚麼要做

這個 Board 先用 YAML → build → static HTML,因為單人每日更新幾次通常不需要常駐 server。SSR 並非做不到,只是要額外處理 authentication、authorization、資料庫和備份。

03 Step-by-step

  1. 如果主要是一人查看、一天更新幾次、沒有手機直接編輯,先使用 SSG。
  2. 如果要多人登入、不同人看不同 Project、手機直接改狀態、即時更新或多個 Agent/API 共用資料,再評估 SSR。
  3. 升級前先畫出 Browser → Server/API → Database 的權限和資料流程。
  4. 安排 access control、audit log、backup、rate limiting 和 secret 管理,再開始遷移。

04 Copy / Command

兩種架構對照
CURRENT / SSG
projects.yaml → Astro build → Static HTML → Cloudflare Pages
適合:個人使用、低頻更新、內容可公開或已受保護

FUTURE / SSR
Browser → Server / Cloudflare → Database / API → Dynamic Dashboard
適合:多人登入、按使用者分資料、即時更新、手機直接編輯

05 完成後應該見到甚麼

  • 你可以說明目前為何用 Static,以及哪幾項需求出現時才值得升級。
  • 無登入/資料庫/即時需求時,先維持簡單架構;不要只為追新技術而加 server。
07 下一章

十章完成。先用測試資料做一次完整 build、review 和 staging preview,再按需要逐步換成自己的資料。

返回 Project Page →

FINAL WORKFLOW

每次更新,都照這個安全次序

先改資料,再測試;先看 preview,再由人決定是否合併和部署。

  1. 更新資料:只改 `src/data/projects.yaml` 中已確認的欄位;未知狀態標示「未確認」,不要猜。
  2. 本機驗證:執行 test、build 和 diff check,再用 `npm run dev` 檢查 Desktop、Mobile、links 和內容。
  3. 檢查變更:確認 branch 是 `staging`,查看 `git status --short` 及 `git diff`,確定沒有 credential、私人資料或未授權檔案。
  4. 推到 Preview:commit 後 push staging,等待 Cloudflare preview build 成功;親自打開部署頁檢查圖片、導覽、手機版及 robots metadata。
  5. 留存紀錄:review 變更、建立日期 snapshot;Morning Brief 只用最新已驗證資料,並標明時間。
  6. 正式發佈:只有完成 review 並獲明確授權後,才透過 Pull Request 合併到 production branch;部署後再讀回正式 routes 確認成功。
每次更新後的本機驗收指令
npm test
npm run build
git diff --check
git status --short
git diff -- src/data/projects.yaml

WORKSHOP COMPLETE

先驗證,再交畀 Agent 長期維護。

由少量測試資料開始;確認資料、權限和部署都正確,再慢慢擴充。

返回 Project Page