[{"data":1,"prerenderedAt":7812},["ShallowReactive",2],{"published-article-paths":3,"search-navigation":348,"\u002Fvi\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues":421,"\u002Fvi\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues-surround":2722},[4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254,256,258,260,262,264,266,268,270,272,274,276,278,280,282,284,286,288,290,292,294,296,298,300,302,304,306,308,310,312,314,316,318,320,322,324,326,328,330,332,334,336,338,340,342,344,346],{"path":5},"\u002Fde\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"path":7},"\u002Fde\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"path":9},"\u002Fde\u002Farticle\u002Fcentralised-the-skills-for-agents",{"path":11},"\u002Fde\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"path":13},"\u002Fde\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"path":15},"\u002Fde\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"path":17},"\u002Fde\u002Farticle\u002Fself-hosted-travel-planner-trek",{"path":19},"\u002Fde\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"path":21},"\u002Fde\u002Farticle\u002Fsetup-antigravity-2",{"path":23},"\u002Fde\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"path":25},"\u002Fde\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"path":27},"\u002Fde\u002Farticle\u002Fsync-obsidian-across-devices",{"path":29},"\u002Fde\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"path":31},"\u002Fde\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"path":33},"\u002Fde\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"path":35},"\u002Fde\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",{"path":37},"\u002Fen\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"path":39},"\u002Fen\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"path":41},"\u002Fen\u002Farticle\u002Fcentralised-the-skills-for-agents",{"path":43},"\u002Fen\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"path":45},"\u002Fen\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"path":47},"\u002Fen\u002Farticle\u002Fhow-to-secure-nodewarden-at-cloudflare",{"path":49},"\u002Fen\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"path":51},"\u002Fen\u002Farticle\u002Fself-hosted-travel-planner-trek",{"path":53},"\u002Fen\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"path":55},"\u002Fen\u002Farticle\u002Fself-hosting-nodewarden-at-cloudflare",{"path":57},"\u002Fen\u002Farticle\u002Fsetup-antigravity-2",{"path":59},"\u002Fen\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"path":61},"\u002Fen\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"path":63},"\u002Fen\u002Farticle\u002Fsync-obsidian-across-devices",{"path":65},"\u002Fen\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"path":67},"\u002Fen\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"path":69},"\u002Fen\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"path":71},"\u002Fen\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",{"path":73},"\u002Fes\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"path":75},"\u002Fes\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"path":77},"\u002Fes\u002Farticle\u002Fcentralised-the-skills-for-agents",{"path":79},"\u002Fes\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"path":81},"\u002Fes\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"path":83},"\u002Fes\u002Farticle\u002Fhow-to-secure-nodewarden-at-cloudflare",{"path":85},"\u002Fes\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"path":87},"\u002Fes\u002Farticle\u002Fself-hosted-travel-planner-trek",{"path":89},"\u002Fes\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"path":91},"\u002Fes\u002Farticle\u002Fself-hosting-nodewarden-at-cloudflare",{"path":93},"\u002Fes\u002Farticle\u002Fsetup-antigravity-2",{"path":95},"\u002Fes\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"path":97},"\u002Fes\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"path":99},"\u002Fes\u002Farticle\u002Fsync-obsidian-across-devices",{"path":101},"\u002Fes\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"path":103},"\u002Fes\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"path":105},"\u002Fes\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"path":107},"\u002Fes\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",{"path":109},"\u002Ffr\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"path":111},"\u002Ffr\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"path":113},"\u002Ffr\u002Farticle\u002Fcentralised-the-skills-for-agents",{"path":115},"\u002Ffr\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"path":117},"\u002Ffr\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"path":119},"\u002Ffr\u002Farticle\u002Fhow-to-secure-nodewarden-at-cloudflare",{"path":121},"\u002Ffr\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"path":123},"\u002Ffr\u002Farticle\u002Fself-hosted-travel-planner-trek",{"path":125},"\u002Ffr\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"path":127},"\u002Ffr\u002Farticle\u002Fself-hosting-nodewarden-at-cloudflare",{"path":129},"\u002Ffr\u002Farticle\u002Fsetup-antigravity-2",{"path":131},"\u002Ffr\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"path":133},"\u002Ffr\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"path":135},"\u002Ffr\u002Farticle\u002Fsync-obsidian-across-devices",{"path":137},"\u002Ffr\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"path":139},"\u002Ffr\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"path":141},"\u002Ffr\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"path":143},"\u002Ffr\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",{"path":145},"\u002Fid\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"path":147},"\u002Fid\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"path":149},"\u002Fid\u002Farticle\u002Fcentralised-the-skills-for-agents",{"path":151},"\u002Fid\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"path":153},"\u002Fid\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"path":155},"\u002Fid\u002Farticle\u002Fhow-to-secure-nodewarden-at-cloudflare",{"path":157},"\u002Fid\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"path":159},"\u002Fid\u002Farticle\u002Fself-hosted-travel-planner-trek",{"path":161},"\u002Fid\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"path":163},"\u002Fid\u002Farticle\u002Fself-hosting-nodewarden-at-cloudflare",{"path":165},"\u002Fid\u002Farticle\u002Fsetup-antigravity-2",{"path":167},"\u002Fid\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"path":169},"\u002Fid\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"path":171},"\u002Fid\u002Farticle\u002Fsync-obsidian-across-devices",{"path":173},"\u002Fid\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"path":175},"\u002Fid\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"path":177},"\u002Fid\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"path":179},"\u002Fid\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",{"path":181},"\u002Fja\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"path":183},"\u002Fja\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"path":185},"\u002Fja\u002Farticle\u002Fcentralised-the-skills-for-agents",{"path":187},"\u002Fja\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"path":189},"\u002Fja\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"path":191},"\u002Fja\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"path":193},"\u002Fja\u002Farticle\u002Fself-hosted-travel-planner-trek",{"path":195},"\u002Fja\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"path":197},"\u002Fja\u002Farticle\u002Fsetup-antigravity-2",{"path":199},"\u002Fja\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"path":201},"\u002Fja\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"path":203},"\u002Fja\u002Farticle\u002Fsync-obsidian-across-devices",{"path":205},"\u002Fja\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"path":207},"\u002Fja\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"path":209},"\u002Fja\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"path":211},"\u002Fja\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",{"path":213},"\u002Fpt\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"path":215},"\u002Fpt\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"path":217},"\u002Fpt\u002Farticle\u002Fcentralised-the-skills-for-agents",{"path":219},"\u002Fpt\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"path":221},"\u002Fpt\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"path":223},"\u002Fpt\u002Farticle\u002Fhow-to-secure-nodewarden-at-cloudflare",{"path":225},"\u002Fpt\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"path":227},"\u002Fpt\u002Farticle\u002Fself-hosted-travel-planner-trek",{"path":229},"\u002Fpt\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"path":231},"\u002Fpt\u002Farticle\u002Fself-hosting-nodewarden-at-cloudflare",{"path":233},"\u002Fpt\u002Farticle\u002Fsetup-antigravity-2",{"path":235},"\u002Fpt\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"path":237},"\u002Fpt\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"path":239},"\u002Fpt\u002Farticle\u002Fsync-obsidian-across-devices",{"path":241},"\u002Fpt\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"path":243},"\u002Fpt\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"path":245},"\u002Fpt\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"path":247},"\u002Fpt\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",{"path":249},"\u002Ftw\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"path":251},"\u002Ftw\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"path":253},"\u002Ftw\u002Farticle\u002Fcentralised-the-skills-for-agents",{"path":255},"\u002Ftw\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"path":257},"\u002Ftw\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"path":259},"\u002Ftw\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"path":261},"\u002Ftw\u002Farticle\u002Fself-hosted-travel-planner-trek",{"path":263},"\u002Ftw\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"path":265},"\u002Ftw\u002Farticle\u002Fsetup-antigravity-2",{"path":267},"\u002Ftw\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"path":269},"\u002Ftw\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"path":271},"\u002Ftw\u002Farticle\u002Fsync-obsidian-across-devices",{"path":273},"\u002Ftw\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"path":275},"\u002Ftw\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"path":277},"\u002Ftw\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"path":279},"\u002Ftw\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",{"path":281},"\u002Fvi\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"path":283},"\u002Fvi\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"path":285},"\u002Fvi\u002Farticle\u002Fcentralised-the-skills-for-agents",{"path":287},"\u002Fvi\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"path":289},"\u002Fvi\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"path":291},"\u002Fvi\u002Farticle\u002Fhow-to-secure-nodewarden-at-cloudflare",{"path":293},"\u002Fvi\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"path":295},"\u002Fvi\u002Farticle\u002Fself-hosted-travel-planner-trek",{"path":297},"\u002Fvi\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"path":299},"\u002Fvi\u002Farticle\u002Fself-hosting-nodewarden-at-cloudflare",{"path":301},"\u002Fvi\u002Farticle\u002Fsetup-antigravity-2",{"path":303},"\u002Fvi\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"path":305},"\u002Fvi\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"path":307},"\u002Fvi\u002Farticle\u002Fsync-obsidian-across-devices",{"path":309},"\u002Fvi\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"path":311},"\u002Fvi\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"path":313},"\u002Fvi\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"path":315},"\u002Fvi\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",{"path":317},"\u002Fzh\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"path":319},"\u002Fzh\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"path":321},"\u002Fzh\u002Farticle\u002Fcentralised-the-skills-for-agents",{"path":323},"\u002Fzh\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"path":325},"\u002Fzh\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"path":327},"\u002Fzh\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"path":329},"\u002Fzh\u002Farticle\u002Fself-hosted-travel-planner-trek",{"path":331},"\u002Fzh\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"path":333},"\u002Fzh\u002Farticle\u002Fsetup-antigravity-2",{"path":335},"\u002Fzh\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"path":337},"\u002Fzh\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"path":339},"\u002Fzh\u002Farticle\u002Fsync-obsidian-across-devices",{"path":341},"\u002Fzh\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"path":343},"\u002Fzh\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"path":345},"\u002Fzh\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"path":347},"\u002Fzh\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",[349,353,357,361,365,369,373,377,381,385,389,393,397,401,405,409,413,417],{"title":350,"path":351,"stem":352},"AI Agent Skills: What They Are & How to Create Them","\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them","en\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them",{"title":354,"path":355,"stem":356},"Bringing Buzz to DeepSeek Harness: Taught to Speak Nostr","\u002Farticle\u002Fbringing-buzz-to-deepseek-harness","en\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",{"title":358,"path":359,"stem":360},"Solving AI Agent Skills Fragmentation with npx skills","\u002Farticle\u002Fcentralised-the-skills-for-agents","en\u002Farticle\u002Fcentralised-the-skills-for-agents",{"title":362,"path":363,"stem":364},"How to Expose Hermes Agent Privately with Cloudflare WARP","\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp","en\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp",{"title":366,"path":367,"stem":368},"How AI Agent Skills Replace Nuxt App Scaffolding Scripts","\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts","en\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",{"title":370,"path":371,"stem":372},"Stop Exposing Your Vault: Secure NodeWarden with Cloudflare","\u002Farticle\u002Fhow-to-secure-nodewarden-at-cloudflare","en\u002Farticle\u002Fhow-to-secure-nodewarden-at-cloudflare",{"title":374,"path":375,"stem":376},"How to Deploy Hermes Agent on a Linux VPS","\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server","en\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server",{"title":378,"path":379,"stem":380},"Self-Host Your Travel Itineraries with TREK and Docker","\u002Farticle\u002Fself-hosted-travel-planner-trek","en\u002Farticle\u002Fself-hosted-travel-planner-trek",{"title":382,"path":383,"stem":384},"Self-Host Block's Buzz: Shared AI Agent Workspace","\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues","en\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",{"title":386,"path":387,"stem":388},"How to Self-Host a BitWarden Compatible Server Nodewarden","\u002Farticle\u002Fself-hosting-nodewarden-at-cloudflare","en\u002Farticle\u002Fself-hosting-nodewarden-at-cloudflare",{"title":390,"path":391,"stem":392},"Google Antigravity 2 Hands-On: Setup & First Impressions","\u002Farticle\u002Fsetup-antigravity-2","en\u002Farticle\u002Fsetup-antigravity-2",{"title":394,"path":395,"stem":396},"NetSuite AI Connector Guide: MCP Setup & Use Cases","\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude","en\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude",{"title":398,"path":399,"stem":400},"Switch Between Multiple Cloudflare WARP Orgs on Mac","\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac","en\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac",{"title":402,"path":403,"stem":404},"How to Sync Obsidian Vaults Across Devices Securely","\u002Farticle\u002Fsync-obsidian-across-devices","en\u002Farticle\u002Fsync-obsidian-across-devices",{"title":406,"path":407,"stem":408},"Testing Claude Fable 5: A Financial Analysis Review","\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis","en\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis",{"title":410,"path":411,"stem":412},"Guide to Browser and Scheduler in Antigravity 2","\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2","en\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2",{"title":414,"path":415,"stem":416},"Build a Persistent AI Memory System on Cloudflare","\u002Farticle\u002Fuse-cloudflare-as-ai-memory","en\u002Farticle\u002Fuse-cloudflare-as-ai-memory",{"title":418,"path":419,"stem":420},"Antigravity 2 in Action: AI Agents, Skills, and MCP","\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2","en\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2",{"id":422,"title":423,"author":424,"body":425,"category":2678,"date":2681,"description":2682,"extension":2683,"image":2684,"imageAlt":2685,"isPublished":772,"meta":2686,"minRead":953,"navigation":772,"path":297,"seo":2712,"stem":2714,"tags":2715,"updatedAt":2720,"__hash__":2721},"article\u002Fvi\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues.md","Tự host Buzz của Block: Không gian cộng tác giữa người và AI","",{"type":426,"value":427,"toc":2648},"minimark",[428,432,439,446,451,454,494,498,504,542,546,551,565,573,581,585,590,606,612,664,703,707,715,721,725,728,968,972,1018,1025,1032,1040,1092,1098,1127,1131,1135,1162,1192,1197,1239,1248,1533,1537,1583,1588,1595,1600,1604,1628,1631,1637,1643,1647,1656,1662,1665,1671,1678,1707,1714,1720,1723,1729,1733,1736,1739,1742,1748,1751,1757,1763,1769,1774,1778,1789,1796,1802,1805,1811,1815,1822,1828,1835,1839,1847,1911,1920,1975,1978,2050,2056,2072,2078,2082,2128,2134,2137,2143,2146,2152,2156,2173,2189,2195,2293,2296,2302,2313,2362,2369,2375,2388,2404,2407,2413,2417,2424,2446,2455,2553,2566,2572,2579,2585,2588,2594,2597,2603,2607,2610,2614,2644],[429,430,431],"p",{},"Sự phân mảnh ngữ cảnh là một trở ngại vô cùng khó chịu khi làm việc với nhiều tác nhân AI (AI agent). Với các cuộc hội thoại ngữ cảnh nằm rải rác trên nhiều công cụ khác nhau, cuối cùng bạn phải tự đóng vai trò là một bộ định tuyến thủ công bằng cách sao chép hội thoại từ Claude Code để dán vào Gemini CLI, rồi lại sao chép từ Gemini CLI dán vào Hermes Agent. Trở ngại này còn tăng lên gấp bội khi có thêm các đồng nghiệp là con người trong cùng một nhóm.",[429,433,434],{},[435,436],"img",{"alt":437,"src":438},"Giao diện người dùng của không gian làm việc cộng tác Buzz hiển thị các kênh trò chuyện và tác nhân AI đang hoạt động","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-workspace-interface.webp",[429,440,441,445],{},[442,443,444],"strong",{},"Buzz",", một không gian làm việc cộng tác nguồn mở, kết nối các nhóm làm việc giữa con người và tác nhân AI vào cùng một môi trường thống nhất. Tại đây, đồng nghiệp và các tác nhân AI chia sẻ chung một lịch sử nhiệm vụ và dự án, chuyển giao công việc cho nhau một cách vô cùng liền mạch.",[447,448,450],"h2",{"id":449},"blocks-buzz-là-gì-không-gian-làm-việc-cộng-tác-cùng-ai-agent","Block's Buzz là gì? Không gian làm việc cộng tác cùng AI Agent",[429,452,453],{},"Buzz là một không gian làm việc cộng tác nguồn mở từ Block (công ty của Jack Dorsey), nơi con người và các tác nhân AI cùng chia sẻ chung các kênh và dự án. Buzz cung cấp các tính năng nổi bật sau:",[455,456,457,464,470,476,482,488],"ul",{},[458,459,460,463],"li",{},[442,461,462],{},"Ngữ cảnh chia sẻ:"," Các kênh là nơi con người và tác nhân AI cộng tác với nhau. Tất cả lịch sử trò chuyện và dự án đều được lưu trữ đầy đủ trong kênh.",[458,465,466,469],{},[442,467,468],{},"Giao tiếp giữa tác nhân với tác nhân:"," Các tác nhân AI có thể giao tiếp trực tiếp với nhau, ngay cả trên các thiết bị khác nhau. Một tác nhân có thể @-mention một tác nhân khác để bàn giao công việc hoặc đối chiếu chéo mã nguồn.",[458,471,472,475],{},[442,473,474],{},"Kích hoạt bằng lượt nhắc (mention-driven):"," Các tác nhân AI chỉ hoạt động khi được @-mention, nếu không sẽ luôn ở trạng thái tĩnh. Khi được nhắc đến, tác nhân sẽ đọc ngữ cảnh liên quan trong kênh và bắt đầu xử lý.",[458,477,478,481],{},[442,479,480],{},"Hệ thống danh tính thống nhất:"," Con người và tác nhân AI sử dụng chung một hệ thống danh tính, được xác thực thông qua các khóa mật mã (cryptographic keys).",[458,483,484,487],{},[442,485,486],{},"Ủy quyền ra lệnh:"," Bạn có thể cấp quyền cho các đồng nghiệp là con người để điều khiển tác nhân của mình, cho phép cả nhóm cùng giao việc và tận dụng các trợ lý kỹ thuật số của nhau.",[458,489,490,493],{},[442,491,492],{},"Máy chủ tự lưu trữ (self-hosted):"," Vì tự vận hành máy chủ, dữ liệu của bạn hoàn toàn nằm dưới quyền kiểm soát của riêng bạn. Bạn có thể chọn ai được tham gia và tự định nghĩa các quy tắc hoạt động.",[447,495,497],{"id":496},"kiến-trúc-mật-mã-dựa-trên-giao-thức-nostr-của-buzz","Kiến trúc mật mã dựa trên giao thức Nostr của Buzz",[429,499,500],{},[435,501],{"alt":502,"src":503},"Sơ đồ kiến trúc mật mã dựa trên giao thức Nostr của không gian làm việc cộng tác Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-nostr-cryptographic-architecture.webp",[455,505,506,512,518,524,530,536],{},[458,507,508,511],{},[442,509,510],{},"Nostr relay đóng vai trò là máy chủ:"," Các tin nhắn, quy trình làm việc, kho lưu trữ và các sự kiện khác được ký bằng mật mã, xác thực và lưu trữ trên một máy chủ Nostr relay. Giao thức Nostr hỗ trợ giao tiếp qua WebSockets và REST API một cách tự nhiên.",[458,513,514,517],{},[442,515,516],{},"Danh tính mật mã thống nhất:"," Cả con người và tác nhân AI đều xác thực bằng khóa mật mã riêng của mình. Danh tính này nằm hoàn toàn ở phía máy khách (client-side) và không bao giờ lưu trữ trên máy chủ.",[458,519,520,523],{},[442,521,522],{},"Thành viên tác nhân hạng nhất:"," Mỗi tác nhân sở hữu danh tính riêng, quyền thành viên kênh và nhật ký kiểm tra (audit trail). Tác nhân kết nối với không gian làm việc thông qua Giao thức Giao tiếp Tác nhân (ACP).",[458,525,526,529],{},[442,527,528],{},"Kho lưu trữ Git phi tập trung:"," Kho lưu trữ mã nguồn được lưu trên bộ nhớ đối tượng tương thích với S3, trong khi các tác vụ, pull request và đánh giá mã (code review) được theo dõi trong nhật ký sự kiện của Nostr. Do đó, kho lưu trữ Git của Buzz được lưu trữ trực tiếp trên Nostr relay chứ không phải GitHub.",[458,531,532,535],{},[442,533,534],{},"Ứng dụng Buzz là một Nostr client:"," Buzz độc lập với Nostr relay; đây là ứng dụng khách trên máy tính\u002Fđiện thoại kết nối đến URL của relay.",[458,537,538,541],{},[442,539,540],{},"Cấu trúc hạ tầng:"," Cơ sở dữ liệu PostgreSQL xử lý lưu trữ sự kiện và tìm kiếm toàn văn, Redis quản lý hệ thống tin nhắn pub\u002Fsub, và MinIO tương thích S3 được dùng làm bộ nhớ lưu trữ tệp đa phương tiện.",[447,543,545],{"id":544},"cách-tự-host-blocks-buzz-relay-trên-máy-chủ-linux-vps","Cách tự host Block's Buzz Relay trên máy chủ Linux VPS",[547,548,550],"h3",{"id":549},"_0-điều-kiện-tiên-quyết","0. Điều kiện tiên quyết",[455,552,553,556,559,562],{},[458,554,555],{},"Một máy chủ Linux VPS",[458,557,558],{},"Tên miền đã trỏ về địa chỉ IP máy chủ của bạn",[458,560,561],{},"Docker và Docker Compose plugin",[458,563,564],{},"Tài khoản Cloudflare (gói dịch vụ miễn phí)",[429,566,567,568,572],{},"Trong hướng dẫn này, chúng ta sẽ chạy Nostr relay trên VPS Ubuntu phía sau một mạng riêng tư của ",[569,570,571],"a",{"href":363},"Cách hiển thị riêng tư Hermes Agent với Cloudflare WARP",". Cấu trúc hệ thống gồm bốn dịch vụ trong Docker Compose — relay, PostgreSQL, Redis và MinIO — kết hợp với Caddy để hỗ trợ HTTPS.",[574,575],"article-card",{"description":576,"image":577,"image-alt":578,"label":579,"min-read":580,"title":571,"to":363},"Tìm hiểu cách hiển thị và truy cập an toàn tác nhân Hermes của bạn trên toàn cầu bằng Cloudflare WARP và Zero Trust mà không cần mở cổng tường lửa đến.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002FVI-Exposing-Hermes-Agent-to-Private-Network-Using-Cloudflare-WARP.webp","Hiển thị an toàn tác nhân Hermes cho mạng riêng bằng Cloudflare Zero Trust và đường hầm WARP","Hướng dẫn liên quan","8",[547,582,584],{"id":583},"_1-cloudflare-dns-và-api-token","1. Cloudflare DNS và API Token",[586,587,589],"h4",{"id":588},"tạo-cloudflare-api-token","Tạo Cloudflare API Token",[591,592,593,600],"ol",{},[458,594,595,596,599],{},"Nhấp vào biểu tượng người dùng ở góc trên cùng bên phải và chọn mục ",[442,597,598],{},"Profile",".",[458,601,602,603,599],{},"Nhấp vào mục ",[442,604,605],{},"API Tokens",[429,607,608],{},[435,609],{"alt":610,"src":611},"Trang hồ sơ người dùng Cloudflare hiển thị menu tạo API Tokens","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fcloudflare-profile-api-tokens.webp",[591,613,615,621,627,648,654,658,661],{"start":614},3,[458,616,617,618,599],{},"Nhấp vào nút ",[442,619,620],{},"Create Token",[458,622,623,624,599],{},"Chọn sử dụng mẫu ",[442,625,626],{},"Edit zone DNS",[458,628,629,630],{},"Cấu hình các thông số cho mẫu như sau:\n",[455,631,632,638],{},[458,633,634,637],{},[442,635,636],{},"Permissions",": Zone — DNS — Edit",[458,639,640,643,644],{},[442,641,642],{},"Zone Resources",": Include — Specific zone — ",[645,646,647],"code",{},"example.com",[458,649,650,651,599],{},"Nhấp chọn ",[442,652,653],{},"Continue to summary",[458,655,650,656,599],{},[442,657,620],{},[458,659,660],{},"Hãy sao chép chuỗi mã thông báo vừa được tạo, vì nó sẽ không hiển thị lại sau khi bạn đóng trang này.",[458,662,663],{},"Kiểm tra xem mã thông báo vừa tạo có hoạt động hay không bằng terminal:",[665,666,670],"pre",{"className":667,"code":668,"language":669,"meta":424,"style":424},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl \"https:\u002F\u002Fapi.cloudflare.com\u002Fclient\u002Fv4\u002Fuser\u002Ftokens\u002Fverify\" -H \"Authorization: Bearer YOUR_TOKEN_HERE\"\n","bash",[645,671,672],{"__ignoreMap":424},[673,674,677,681,685,689,692,695,697,700],"span",{"class":675,"line":676},"line",1,[673,678,680],{"class":679},"sBMFI","curl",[673,682,684],{"class":683},"sMK4o"," \"",[673,686,688],{"class":687},"sfazB","https:\u002F\u002Fapi.cloudflare.com\u002Fclient\u002Fv4\u002Fuser\u002Ftokens\u002Fverify",[673,690,691],{"class":683},"\"",[673,693,694],{"class":687}," -H",[673,696,684],{"class":683},[673,698,699],{"class":687},"Authorization: Bearer YOUR_TOKEN_HERE",[673,701,702],{"class":683},"\"\n",[586,704,706],{"id":705},"bản-ghi-dns","Bản ghi DNS",[455,708,709],{},[458,710,711,712,599],{},"Tạo một bản ghi A mới và thiết lập ở trạng thái ",[442,713,714],{},"DNS only",[429,716,717],{},[435,718],{"alt":719,"src":720},"Cấu hình bản ghi DNS A cho tên miền Buzz trong bảng điều khiển Cloudflare với trạng thái proxy là DNS only","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fcloudflare-dns-a-record-configuration.webp",[547,722,724],{"id":723},"_2-cài-đặt-docker-trên-ubuntu","2. Cài đặt Docker trên Ubuntu",[429,726,727],{},"Chạy các lệnh sau trực tiếp trên Ubuntu để thực hiện cài đặt Docker:",[665,729,731],{"className":667,"code":730,"language":669,"meta":424,"style":424},"# Add Docker's official GPG key and set up the Docker repository\ncurl -fsSL https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu\u002Fgpg | sudo gpg --dearmor -o \u002Fusr\u002Fshare\u002Fkeyrings\u002Fdocker-archive-keyring.gpg\n\n# Add the official Docker repository\necho \"deb [arch=amd64 signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fdocker-archive-keyring.gpg] https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu $(lsb_release -cs) stable\" | sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.list > \u002Fdev\u002Fnull\n\n# Update package list\nsudo apt update\n\n# Install Docker Engine, Docker Community Edition, and containerd runtime\nsudo apt install docker-ce docker-ce-cli containerd.io -y\n\n# Start automatically when the system boots\nsudo systemctl enable docker\n\n# Verify docker is installed\ndocker --version\n\nsudo apt install -y docker-compose-plugin\n\n# Verify the compose plugin is installed\ndocker compose version\n\n",[645,732,733,739,768,774,780,825,830,836,848,853,859,881,886,892,906,911,917,926,931,946,951,957],{"__ignoreMap":424},[673,734,735],{"class":675,"line":676},[673,736,738],{"class":737},"sHwdD","# Add Docker's official GPG key and set up the Docker repository\n",[673,740,742,744,747,750,753,756,759,762,765],{"class":675,"line":741},2,[673,743,680],{"class":679},[673,745,746],{"class":687}," -fsSL",[673,748,749],{"class":687}," https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu\u002Fgpg",[673,751,752],{"class":683}," |",[673,754,755],{"class":679}," sudo",[673,757,758],{"class":687}," gpg",[673,760,761],{"class":687}," --dearmor",[673,763,764],{"class":687}," -o",[673,766,767],{"class":687}," \u002Fusr\u002Fshare\u002Fkeyrings\u002Fdocker-archive-keyring.gpg\n",[673,769,770],{"class":675,"line":614},[673,771,773],{"emptyLinePlaceholder":772},true,"\n",[673,775,777],{"class":675,"line":776},4,[673,778,779],{"class":737},"# Add the official Docker repository\n",[673,781,783,787,789,792,795,798,801,804,807,809,811,813,816,819,822],{"class":675,"line":782},5,[673,784,786],{"class":785},"s2Zo4","echo",[673,788,684],{"class":683},[673,790,791],{"class":687},"deb [arch=amd64 signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fdocker-archive-keyring.gpg] https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu ",[673,793,794],{"class":683},"$(",[673,796,797],{"class":679},"lsb_release",[673,799,800],{"class":687}," -cs",[673,802,803],{"class":683},")",[673,805,806],{"class":687}," stable",[673,808,691],{"class":683},[673,810,752],{"class":683},[673,812,755],{"class":679},[673,814,815],{"class":687}," tee",[673,817,818],{"class":687}," \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.list",[673,820,821],{"class":683}," >",[673,823,824],{"class":687}," \u002Fdev\u002Fnull\n",[673,826,828],{"class":675,"line":827},6,[673,829,773],{"emptyLinePlaceholder":772},[673,831,833],{"class":675,"line":832},7,[673,834,835],{"class":737},"# Update package list\n",[673,837,839,842,845],{"class":675,"line":838},8,[673,840,841],{"class":679},"sudo",[673,843,844],{"class":687}," apt",[673,846,847],{"class":687}," update\n",[673,849,851],{"class":675,"line":850},9,[673,852,773],{"emptyLinePlaceholder":772},[673,854,856],{"class":675,"line":855},10,[673,857,858],{"class":737},"# Install Docker Engine, Docker Community Edition, and containerd runtime\n",[673,860,862,864,866,869,872,875,878],{"class":675,"line":861},11,[673,863,841],{"class":679},[673,865,844],{"class":687},[673,867,868],{"class":687}," install",[673,870,871],{"class":687}," docker-ce",[673,873,874],{"class":687}," docker-ce-cli",[673,876,877],{"class":687}," containerd.io",[673,879,880],{"class":687}," -y\n",[673,882,884],{"class":675,"line":883},12,[673,885,773],{"emptyLinePlaceholder":772},[673,887,889],{"class":675,"line":888},13,[673,890,891],{"class":737},"# Start automatically when the system boots\n",[673,893,895,897,900,903],{"class":675,"line":894},14,[673,896,841],{"class":679},[673,898,899],{"class":687}," systemctl",[673,901,902],{"class":687}," enable",[673,904,905],{"class":687}," docker\n",[673,907,909],{"class":675,"line":908},15,[673,910,773],{"emptyLinePlaceholder":772},[673,912,914],{"class":675,"line":913},16,[673,915,916],{"class":737},"# Verify docker is installed\n",[673,918,920,923],{"class":675,"line":919},17,[673,921,922],{"class":679},"docker",[673,924,925],{"class":687}," --version\n",[673,927,929],{"class":675,"line":928},18,[673,930,773],{"emptyLinePlaceholder":772},[673,932,934,936,938,940,943],{"class":675,"line":933},19,[673,935,841],{"class":679},[673,937,844],{"class":687},[673,939,868],{"class":687},[673,941,942],{"class":687}," -y",[673,944,945],{"class":687}," docker-compose-plugin\n",[673,947,949],{"class":675,"line":948},20,[673,950,773],{"emptyLinePlaceholder":772},[673,952,954],{"class":675,"line":953},21,[673,955,956],{"class":737},"# Verify the compose plugin is installed\n",[673,958,960,962,965],{"class":675,"line":959},22,[673,961,922],{"class":679},[673,963,964],{"class":687}," compose",[673,966,967],{"class":687}," version\n",[547,969,971],{"id":970},"_3-tải-mã-nguồn-clone-và-cấu-hình","3. Tải mã nguồn (Clone) và cấu hình",[665,973,975],{"className":667,"code":974,"language":669,"meta":424,"style":424},"git clone https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz.git\n\ncd buzz\u002Fdeploy\u002Fcompose\ncp .env.example .env\nnano .env\n",[645,976,977,988,992,1000,1011],{"__ignoreMap":424},[673,978,979,982,985],{"class":675,"line":676},[673,980,981],{"class":679},"git",[673,983,984],{"class":687}," clone",[673,986,987],{"class":687}," https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz.git\n",[673,989,990],{"class":675,"line":741},[673,991,773],{"emptyLinePlaceholder":772},[673,993,994,997],{"class":675,"line":614},[673,995,996],{"class":785},"cd",[673,998,999],{"class":687}," buzz\u002Fdeploy\u002Fcompose\n",[673,1001,1002,1005,1008],{"class":675,"line":776},[673,1003,1004],{"class":679},"cp",[673,1006,1007],{"class":687}," .env.example",[673,1009,1010],{"class":687}," .env\n",[673,1012,1013,1016],{"class":675,"line":782},[673,1014,1015],{"class":679},"nano",[673,1017,1010],{"class":687},[429,1019,1020,1021,1024],{},"Chỉnh sửa tệp cấu hình ",[645,1022,1023],{},".env"," theo từng nhóm thông số:",[455,1026,1027],{},[458,1028,1029],{},[442,1030,1031],{},"Cấu hình Domain:",[665,1033,1038],{"className":1034,"code":1036,"language":1037},[1035],"language-text","BUZZ_DOMAIN=buzz.pafor.me\nRELAY_URL=wss:\u002F\u002Fbuzz.pafor.me\nBUZZ_PAIRING_RELAY_URL=wss:\u002F\u002Fbuzz.pafor.me\u002Fpair\nBUZZ_MEDIA_BASE_URL=https:\u002F\u002Fbuzz.pafor.me\u002Fmedia\nBUZZ_MEDIA_SERVER_DOMAIN=buzz.pafor.me\nBUZZ_CORS_ORIGINS=https:\u002F\u002Fbuzz.pafor.me\n","text",[645,1039,1036],{"__ignoreMap":424},[455,1041,1042,1052],{},[458,1043,1044,1047,1048,1051],{},[442,1045,1046],{},"Khóa chủ sở hữu:"," ",[645,1049,1050],{},"RELAY_OWNER_PUBKEY"," yêu cầu khóa công khai dạng hex dài 64 ký tự của bạn. Hãy tạo một danh tính mới trong ứng dụng máy tính trước ('Create a new identity key' → sao chép mã công khai của bạn, có định dạng npub), sau đó chuyển đổi nó sang dạng hex.",[458,1053,1054,1057],{},[442,1055,1056],{},"Khóa bí mật (Secrets):",[455,1058,1059,1071,1086],{},[458,1060,1061,1062,1066,1067,1070],{},"Tạo các khóa bí mật bằng cách sử dụng ",[569,1063,1065],{"href":1064},"\u002Fvi\u002Ftools\u002Fsecret-key-hex","công cụ trực tuyến"," này hoặc chạy lệnh ",[645,1068,1069],{},"openssl rand -hex 32"," (thực hiện bảy lần).",[458,1072,1073,1074,1077,1078,1081,1082,1085],{},"Thay thế mọi chỗ trống ",[645,1075,1076],{},"CHANGE_ME",": ",[645,1079,1080],{},"BUZZ_RELAY_PRIVATE_KEY",", ",[645,1083,1084],{},"BUZZ_GIT_HOOK_HMAC_SECRET",", mật khẩu Postgres\u002FRedis\u002FTypesense, cũng như khóa truy cập\u002Fbí mật của S3.",[458,1087,1088,1089,599],{},"Việc quên thay đổi các placeholder này là nguyên nhân phổ biến nhất khiến container bị lặp lại quá trình khởi động; hãy kiểm tra lại bằng lệnh ",[645,1090,1091],{},"grep CHANGE_ME .env",[665,1093,1096],{"className":1094,"code":1095,"language":1037},[1035],"    BUZZ_RELAY_PRIVATE_KEY=CHANGE_ME_64_HEX_PRIVATE_KEY\n    BUZZ_GIT_HOOK_HMAC_SECRET=CHANGE_ME_RANDOM_64_HEX\n    POSTGRES_PASSWORD=CHANGE_ME_RANDOM_PASSWORD\n    REDIS_PASSWORD=CHANGE_ME_RANDOM_PASSWORD\n    TYPESENSE_API_KEY=CHANGE_ME_RANDOM_API_KEY\n    BUZZ_S3_ACCESS_KEY=CHANGE_ME_RANDOM_ACCESS_KEY\n    BUZZ_S3_SECRET_KEY=CHANGE_ME_RANDOM_SECRET_KEY\n",[645,1097,1095],{"__ignoreMap":424},[455,1099,1100],{},[458,1101,1102,1105],{},[442,1103,1104],{},"Cấu hình khác:",[455,1106,1107,1114],{},[458,1108,1109,1110,1113],{},"Thêm biến môi trường ",[645,1111,1112],{},"CLOUDFLARE_API_TOKEN"," và gán giá trị API token đã tạo ở bước trước. Việc này là bắt buộc đối với Caddy.",[458,1115,1116,1117,1081,1119,1122,1123,1126],{},"Buzz mặc định mở quyền tự do tham gia — bất kỳ ai biết URL relay của bạn đều có thể xác thực và kết nối. Hãy thiết lập ",[645,1118,1050],{},[645,1120,1121],{},"BUZZ_REQUIRE_RELAY_MEMBERSHIP=true",", và ",[645,1124,1125],{},"BUZZ_REQUIRE_AUTH_TOKEN=true"," để tăng tính bảo mật.",[547,1128,1130],{"id":1129},"_4-kích-hoạt-https-với-caddy","4. Kích hoạt HTTPS với Caddy",[586,1132,1134],{"id":1133},"xây-dựng-hình-ảnh-caddy-tùy-chỉnh-kèm-theo-mô-đun-dns-cloudflare","Xây dựng hình ảnh Caddy tùy chỉnh kèm theo mô-đun DNS Cloudflare",[455,1136,1137,1148,1159],{},[458,1138,1139,1140,1143,1144,1147],{},"Chúng ta thiết lập DNS-01 của Cloudflare cho Caddy. Phương thức DNS-01 hoạt động bằng cách yêu cầu plugin viết một bản ghi TXT ",[645,1141,1142],{},"_acme-challenge.buzz.pafor.me"," lên ",[442,1145,1146],{},"DNS công khai",";",[458,1149,1150,1151,1154,1155,1158],{},"Sau đó Let's Encrypt sẽ truy vấn bản ghi này từ internet để xác minh quyền sở hữu tên miền của bạn. Điều này nghĩa là ",[645,1152,1153],{},"pafor.me"," phải là một vùng (zone) công khai trong tài khoản Cloudflare của bạn — không thể chỉ là một hostname nội bộ chỉ tồn tại trong DNS riêng tư của Zero Trust \u002F WARP. Nếu ",[645,1156,1157],{},"buzz.pafor.me"," chỉ được phân giải nội bộ và không có vùng công khai, DNS-01 sẽ lỗi và đòi hỏi phương pháp xác thực khác.",[458,1160,1161],{},"Thêm cấu hình sau vào tệp Caddyfile:",[665,1163,1167],{"className":1164,"code":1165,"language":1166,"meta":424,"style":424},"language-yml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}\n}\n","yml",[645,1168,1169,1174,1188],{"__ignoreMap":424},[673,1170,1171],{"class":675,"line":676},[673,1172,1173],{"class":683},"{\n",[673,1175,1176,1179,1182,1185],{"class":675,"line":741},[673,1177,1178],{"class":687},"  acme_dns cloudflare",[673,1180,1181],{"class":683}," {",[673,1183,1184],{"class":687},"env.CLOUDFLARE_API_TOKEN",[673,1186,1187],{"class":683},"}\n",[673,1189,1190],{"class":675,"line":614},[673,1191,1187],{"class":683},[455,1193,1194],{},[458,1195,1196],{},"Tạo một tệp Dockerfile.caddy với nội dung sau, tệp này được yêu cầu bởi compose.caddy.yml:",[665,1198,1200],{"className":1164,"code":1199,"language":1166,"meta":424,"style":424},"FROM caddy:2-builder AS builder\n\nRUN xcaddy build \\\n    --with github.com\u002Fcaddy-dns\u002Fcloudflare\n\nFROM caddy:2-alpine\n\nCOPY --from=builder \u002Fusr\u002Fbin\u002Fcaddy \u002Fusr\u002Fbin\u002Fcaddy\n",[645,1201,1202,1207,1211,1216,1221,1225,1230,1234],{"__ignoreMap":424},[673,1203,1204],{"class":675,"line":676},[673,1205,1206],{"class":687},"FROM caddy:2-builder AS builder\n",[673,1208,1209],{"class":675,"line":741},[673,1210,773],{"emptyLinePlaceholder":772},[673,1212,1213],{"class":675,"line":614},[673,1214,1215],{"class":687},"RUN xcaddy build \\\n",[673,1217,1218],{"class":675,"line":776},[673,1219,1220],{"class":687},"    --with github.com\u002Fcaddy-dns\u002Fcloudflare\n",[673,1222,1223],{"class":675,"line":782},[673,1224,773],{"emptyLinePlaceholder":772},[673,1226,1227],{"class":675,"line":827},[673,1228,1229],{"class":687},"FROM caddy:2-alpine\n",[673,1231,1232],{"class":675,"line":832},[673,1233,773],{"emptyLinePlaceholder":772},[673,1235,1236],{"class":675,"line":838},[673,1237,1238],{"class":687},"COPY --from=builder \u002Fusr\u002Fbin\u002Fcaddy \u002Fusr\u002Fbin\u002Fcaddy\n",[455,1240,1241],{},[458,1242,1243,1244,1247],{},"Chỉnh sửa ",[645,1245,1246],{},"compose.caddy.yml"," để sử dụng image với mô-đun Cloudflare và gán API token của Cloudflare:",[665,1249,1251],{"className":1164,"code":1250,"language":1166,"meta":424,"style":424},"services:\n  relay:\n    ports: !reset []\n\n  caddy:\n    build:\n      context: .\n      dockerfile: Dockerfile.caddy\n    image: buzz-caddy:cloudflare\n    depends_on:\n      relay:\n        condition: service_healthy\n    environment:\n      BUZZ_DOMAIN: ${BUZZ_DOMAIN:?set BUZZ_DOMAIN}\n      CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_API_TOKEN:?set CLOUDFLARE_API_TOKEN}\n    ports:\n      - \"${CADDY_HTTP_PORT:-80}:80\"\n      - \"${CADDY_HTTPS_PORT:-443}:443\"\n    volumes:\n      - .\u002FCaddyfile:\u002Fetc\u002Fcaddy\u002FCaddyfile:ro\n      - buzz-caddy-data:\u002Fdata\n      - buzz-caddy-config:\u002Fconfig\n    restart: unless-stopped\n    networks:\n      - buzz-net\n\nvolumes:\n  buzz-caddy-data:\n    labels:\n      com.buzz.volume: caddy-data\n  buzz-caddy-config:\n    labels:\n      com.buzz.volume: caddy-config\n",[645,1252,1253,1262,1269,1284,1288,1295,1302,1313,1323,1333,1340,1347,1357,1364,1374,1384,1390,1402,1413,1420,1427,1434,1441,1452,1460,1468,1473,1481,1489,1497,1508,1516,1523],{"__ignoreMap":424},[673,1254,1255,1259],{"class":675,"line":676},[673,1256,1258],{"class":1257},"swJcz","services",[673,1260,1261],{"class":683},":\n",[673,1263,1264,1267],{"class":675,"line":741},[673,1265,1266],{"class":1257},"  relay",[673,1268,1261],{"class":683},[673,1270,1271,1274,1277,1281],{"class":675,"line":614},[673,1272,1273],{"class":1257},"    ports",[673,1275,1276],{"class":683},":",[673,1278,1280],{"class":1279},"spNyl"," !reset",[673,1282,1283],{"class":683}," []\n",[673,1285,1286],{"class":675,"line":776},[673,1287,773],{"emptyLinePlaceholder":772},[673,1289,1290,1293],{"class":675,"line":782},[673,1291,1292],{"class":1257},"  caddy",[673,1294,1261],{"class":683},[673,1296,1297,1300],{"class":675,"line":827},[673,1298,1299],{"class":1257},"    build",[673,1301,1261],{"class":683},[673,1303,1304,1307,1309],{"class":675,"line":832},[673,1305,1306],{"class":1257},"      context",[673,1308,1276],{"class":683},[673,1310,1312],{"class":1311},"sbssI"," .\n",[673,1314,1315,1318,1320],{"class":675,"line":838},[673,1316,1317],{"class":1257},"      dockerfile",[673,1319,1276],{"class":683},[673,1321,1322],{"class":687}," Dockerfile.caddy\n",[673,1324,1325,1328,1330],{"class":675,"line":850},[673,1326,1327],{"class":1257},"    image",[673,1329,1276],{"class":683},[673,1331,1332],{"class":687}," buzz-caddy:cloudflare\n",[673,1334,1335,1338],{"class":675,"line":855},[673,1336,1337],{"class":1257},"    depends_on",[673,1339,1261],{"class":683},[673,1341,1342,1345],{"class":675,"line":861},[673,1343,1344],{"class":1257},"      relay",[673,1346,1261],{"class":683},[673,1348,1349,1352,1354],{"class":675,"line":883},[673,1350,1351],{"class":1257},"        condition",[673,1353,1276],{"class":683},[673,1355,1356],{"class":687}," service_healthy\n",[673,1358,1359,1362],{"class":675,"line":888},[673,1360,1361],{"class":1257},"    environment",[673,1363,1261],{"class":683},[673,1365,1366,1369,1371],{"class":675,"line":894},[673,1367,1368],{"class":1257},"      BUZZ_DOMAIN",[673,1370,1276],{"class":683},[673,1372,1373],{"class":687}," ${BUZZ_DOMAIN:?set BUZZ_DOMAIN}\n",[673,1375,1376,1379,1381],{"class":675,"line":908},[673,1377,1378],{"class":1257},"      CLOUDFLARE_API_TOKEN",[673,1380,1276],{"class":683},[673,1382,1383],{"class":687}," ${CLOUDFLARE_API_TOKEN:?set CLOUDFLARE_API_TOKEN}\n",[673,1385,1386,1388],{"class":675,"line":913},[673,1387,1273],{"class":1257},[673,1389,1261],{"class":683},[673,1391,1392,1395,1397,1400],{"class":675,"line":919},[673,1393,1394],{"class":683},"      -",[673,1396,684],{"class":683},[673,1398,1399],{"class":687},"${CADDY_HTTP_PORT:-80}:80",[673,1401,702],{"class":683},[673,1403,1404,1406,1408,1411],{"class":675,"line":928},[673,1405,1394],{"class":683},[673,1407,684],{"class":683},[673,1409,1410],{"class":687},"${CADDY_HTTPS_PORT:-443}:443",[673,1412,702],{"class":683},[673,1414,1415,1418],{"class":675,"line":933},[673,1416,1417],{"class":1257},"    volumes",[673,1419,1261],{"class":683},[673,1421,1422,1424],{"class":675,"line":948},[673,1423,1394],{"class":683},[673,1425,1426],{"class":687}," .\u002FCaddyfile:\u002Fetc\u002Fcaddy\u002FCaddyfile:ro\n",[673,1428,1429,1431],{"class":675,"line":953},[673,1430,1394],{"class":683},[673,1432,1433],{"class":687}," buzz-caddy-data:\u002Fdata\n",[673,1435,1436,1438],{"class":675,"line":959},[673,1437,1394],{"class":683},[673,1439,1440],{"class":687}," buzz-caddy-config:\u002Fconfig\n",[673,1442,1444,1447,1449],{"class":675,"line":1443},23,[673,1445,1446],{"class":1257},"    restart",[673,1448,1276],{"class":683},[673,1450,1451],{"class":687}," unless-stopped\n",[673,1453,1455,1458],{"class":675,"line":1454},24,[673,1456,1457],{"class":1257},"    networks",[673,1459,1261],{"class":683},[673,1461,1463,1465],{"class":675,"line":1462},25,[673,1464,1394],{"class":683},[673,1466,1467],{"class":687}," buzz-net\n",[673,1469,1471],{"class":675,"line":1470},26,[673,1472,773],{"emptyLinePlaceholder":772},[673,1474,1476,1479],{"class":675,"line":1475},27,[673,1477,1478],{"class":1257},"volumes",[673,1480,1261],{"class":683},[673,1482,1484,1487],{"class":675,"line":1483},28,[673,1485,1486],{"class":1257},"  buzz-caddy-data",[673,1488,1261],{"class":683},[673,1490,1492,1495],{"class":675,"line":1491},29,[673,1493,1494],{"class":1257},"    labels",[673,1496,1261],{"class":683},[673,1498,1500,1503,1505],{"class":675,"line":1499},30,[673,1501,1502],{"class":1257},"      com.buzz.volume",[673,1504,1276],{"class":683},[673,1506,1507],{"class":687}," caddy-data\n",[673,1509,1511,1514],{"class":675,"line":1510},31,[673,1512,1513],{"class":1257},"  buzz-caddy-config",[673,1515,1261],{"class":683},[673,1517,1519,1521],{"class":675,"line":1518},32,[673,1520,1494],{"class":1257},[673,1522,1261],{"class":683},[673,1524,1526,1528,1530],{"class":675,"line":1525},33,[673,1527,1502],{"class":1257},[673,1529,1276],{"class":683},[673,1531,1532],{"class":687}," caddy-config\n",[586,1534,1536],{"id":1535},"khởi-động-các-docker-container","Khởi động các Docker container",[665,1538,1540],{"className":667,"code":1539,"language":669,"meta":424,"style":424},"docker compose -f compose.yml -f compose.caddy.yml up -d\n\n#Check the Docker status\ndocker compose ps\n",[645,1541,1542,1565,1569,1574],{"__ignoreMap":424},[673,1543,1544,1546,1548,1551,1554,1556,1559,1562],{"class":675,"line":676},[673,1545,922],{"class":679},[673,1547,964],{"class":687},[673,1549,1550],{"class":687}," -f",[673,1552,1553],{"class":687}," compose.yml",[673,1555,1550],{"class":687},[673,1557,1558],{"class":687}," compose.caddy.yml",[673,1560,1561],{"class":687}," up",[673,1563,1564],{"class":687}," -d\n",[673,1566,1567],{"class":675,"line":741},[673,1568,773],{"emptyLinePlaceholder":772},[673,1570,1571],{"class":675,"line":614},[673,1572,1573],{"class":737},"#Check the Docker status\n",[673,1575,1576,1578,1580],{"class":675,"line":776},[673,1577,922],{"class":679},[673,1579,964],{"class":687},[673,1581,1582],{"class":687}," ps\n",[435,1584],{"src":1585,"alt":1586,"style":1587},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fdocker-compose-ps-status-terminal.webp","Cửa sổ terminal hiển thị các container đang chạy cho dịch vụ Buzz qua lệnh docker compose ps","max-width: 700px; width: 100%; height: auto;",[429,1589,1590,1591,1594],{},"Mở trình duyệt web của bạn và truy cập ",[645,1592,1593],{},"http:\u002F\u002Fbuzz.pafor.me"," để kiểm tra xem relay đã hoạt động bình thường chưa.",[435,1596],{"src":1597,"alt":1598,"style":1599},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-relay-running-browser-verification.webp","Xác minh trên trình duyệt hiển thị phản hồi thành công từ Block's Buzz relay tự lưu trữ","max-width: 500px; width: 100%; height: auto;",[547,1601,1603],{"id":1602},"bước-5-thiết-lập-sao-lưu-tự-động-ngay-từ-ngày-đầu","Bước 5: Thiết lập sao lưu tự động ngay từ ngày đầu",[665,1605,1607],{"className":667,"code":1606,"language":669,"meta":424,"style":424},"mkdir -p \u002Fbuzz_backups\ncrontab -e\n",[645,1608,1609,1620],{"__ignoreMap":424},[673,1610,1611,1614,1617],{"class":675,"line":676},[673,1612,1613],{"class":679},"mkdir",[673,1615,1616],{"class":687}," -p",[673,1618,1619],{"class":687}," \u002Fbuzz_backups\n",[673,1621,1622,1625],{"class":675,"line":741},[673,1623,1624],{"class":679},"crontab",[673,1626,1627],{"class":687}," -e\n",[429,1629,1630],{},"Cài đặt cron job sao lưu cơ sở dữ liệu hàng đêm:",[665,1632,1635],{"className":1633,"code":1634,"language":1037},[1035],"0 3 * * * cd \u002Fhome\u002F\u003Cuser>\u002Fbuzz\u002Fdeploy\u002Fcompose && docker compose exec -T postgres pg_dump -U buzz buzz > \u002Fbuzz_backups\u002Fbuzz-$(date +\\%Y\\%m\\%d).sql\n",[645,1636,1634],{"__ignoreMap":424},[429,1638,1639,1640,1642],{},"Lưu ý: Hãy coi ",[645,1641,1080],{}," là vĩnh viễn. Các sự kiện được ký bằng khóa này sẽ bị lỗi xác thực nếu khóa bị thay đổi; một cơ sở dữ liệu được khôi phục nhưng kết hợp với một khóa mới tạo sẽ không được công nhận là cùng một relay.",[447,1644,1646],{"id":1645},"thiết-lập-buzz-desktop-client-và-danh-tính-nostr","Thiết lập Buzz Desktop Client và Danh tính Nostr",[429,1648,1649,1650,1655],{},"Tải ứng dụng khách Buzz cho máy tính từ ",[569,1651,1652],{"href":1652,"rel":1653},"https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz\u002Freleases",[1654],"nofollow"," và cài đặt. Điền thông tin hồ sơ cho đến khi bạn tới màn hình \"Join or create a community\".",[429,1657,1658],{},[435,1659],{"alt":1660,"src":1661},"Màn hình thiết lập ban đầu của Buzz Desktop Client để tham gia hoặc tạo cộng đồng","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-setup-community.webp",[429,1663,1664],{},"Nhấp vào \"Join a community\" và sao chép khóa công khai của bạn.",[429,1666,1667],{},[435,1668],{"alt":1669,"src":1670},"Ứng dụng khách Buzz hiển thị danh tính khóa công khai trước khi tham gia cộng đồng","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-join-community-public-key.webp",[429,1672,1673,1674,1677],{},"Chạy lệnh sau trên ",[442,1675,1676],{},"VPS"," để tự thêm mình làm thành viên đầu tiên:",[665,1679,1681],{"className":667,"code":1680,"language":669,"meta":424,"style":424},"docker compose exec relay buzz-admin add-member --pubkey npub1yourkeyhere\n",[645,1682,1683],{"__ignoreMap":424},[673,1684,1685,1687,1689,1692,1695,1698,1701,1704],{"class":675,"line":676},[673,1686,922],{"class":679},[673,1688,964],{"class":687},[673,1690,1691],{"class":687}," exec",[673,1693,1694],{"class":687}," relay",[673,1696,1697],{"class":687}," buzz-admin",[673,1699,1700],{"class":687}," add-member",[673,1702,1703],{"class":687}," --pubkey",[673,1705,1706],{"class":687}," npub1yourkeyhere\n",[429,1708,1709,1710,1713],{},"Nhập ",[645,1711,1712],{},"wss:\u002F\u002Fbuzz.pafor.me"," vào mục URL cộng đồng và nhấn \"Next\".",[429,1715,1716],{},[435,1717],{"alt":1718,"src":1719},"Nhập URL relay cộng đồng tự lưu trữ vào ứng dụng Buzz trên máy tính","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-input-community-url.webp",[429,1721,1722],{},"Nhập tên hiển thị và nhấn nút Next.",[429,1724,1725],{},[435,1726],{"alt":1727,"src":1728},"Màn hình cấu hình hồ sơ trong ứng dụng Buzz để nhập tên hiển thị","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-profile-name-input.webp",[547,1730,1732],{"id":1731},"kênh-channels-và-tác-nhân","Kênh (Channels) và Tác nhân",[429,1734,1735],{},"Kênh là các nhóm nhiệm vụ hoặc nhóm dự án. Hãy tạo một kênh riêng cho từng nhiệm vụ oder dự án và mời mọi người cùng các AI agent tham gia.",[429,1737,1738],{},"Mọi thông tin trong kênh được chia sẻ hoàn toàn tự động, loại bỏ việc phải giải thích lại yêu cầu cho từng thành viên một. Mỗi tác nhân AI có thể được gọi tên bằng ký tự @ và sẽ đọc các tin nhắn liên quan để xử lý. Ngoài ra, các tác nhân AI cũng có thể @ nhắc đến nhau.",[429,1740,1741],{},"Hãy thử gửi tin nhắn trực tiếp (DM) cho một tác nhân AI đã cấu hình sẵn",[429,1743,1744],{},[435,1745],{"alt":1746,"src":1747},"Gửi tin nhắn trực tiếp cho tác nhân AI trong ứng dụng khách Buzz trên máy tính","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-dm-agent.webp",[429,1749,1750],{},"Hãy thử tạo một kênh mới và thêm một số tác nhân AI vào kênh",[429,1752,1753],{},[435,1754],{"alt":1755,"src":1756},"Tạo kênh nhiệm vụ hoặc dự án mới trong ứng dụng Buzz trên máy tính","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-create-channel-dialog.webp",[429,1758,1759],{},[435,1760],{"alt":1761,"src":1762},"Thêm thành viên con người và tác nhân AI vào kênh vừa tạo","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-add-agents-to-channel.webp",[429,1764,1765],{},[435,1766],{"alt":1767,"src":1768},"Chế độ xem kênh hoạt động hiển thị lịch sử trò chuyện tổng hợp và nhiệm vụ dự án","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-channel-view.webp",[435,1770],{"src":1771,"alt":1772,"style":1773},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-channel-active-agents.webp","Xem chi tiết các tác nhân AI đang hoạt động được tích hợp vào kênh dự án cộng tác","max-width: 367px; width: 100%; height: auto;",[547,1775,1777],{"id":1776},"kích-hoạt-môi-trường-chạy-runtimes-của-tác-nhân","Kích hoạt môi trường chạy (Runtimes) của tác nhân",[429,1779,1780,1781,1784,1785,1788],{},"Môi trường chạy mặc định dựa trên cơ chế tự phát hiện tệp chạy nhị phân (chẳng hạn như ",[645,1782,1783],{},"hermes-acp",") trong các thư mục chuẩn như ",[645,1786,1787],{},"~\u002F.local\u002Fbin",". Nếu một công cụ được cài đặt ở một vị trí khác chuẩn, Buzz sẽ không thể tìm thấy nó.",[429,1790,1791,1792,1795],{},"Đối với Kimi Code, mã định danh tác nhân là kimi, và Buzz sẽ tìm kiếm tệp nhị phân tại ",[645,1793,1794],{},"~\u002F.local\u002Fbin\u002Fkimi",". Tạo một liên kết tượng trưng (symbolic link) sẽ giải quyết được vấn đề:",[665,1797,1800],{"className":1798,"code":1799,"language":1037},[1035],"ln -s kimi-cli \u002FUsers\u002F\u003Cuser>\u002F.local\u002Fbin\u002Fkimi\n",[645,1801,1799],{"__ignoreMap":424},[429,1803,1804],{},"Giờ đây, Kimi Code sẽ xuất hiện trong danh sách Runtimes của tác nhân.",[429,1806,1807],{},[435,1808],{"alt":1809,"src":1810},"Cài đặt ứng dụng Buzz hiển thị các runtimes của tác nhân AI đã cấu hình bao gồm Kimi","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-settings-agent-runtimes-list.webp",[547,1812,1814],{"id":1813},"dự-án-và-kho-lưu-trữ","Dự án và Kho lưu trữ",[429,1816,1817,1818,1821],{},"Kích hoạt tính năng '",[442,1819,1820],{},"Projects","' trong Settings → Experiments trước tiên:",[429,1823,1824],{},[435,1825],{"alt":1826,"src":1827},"Kích hoạt tính năng thử nghiệm Projects trong tab cài đặt của Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-settings-experiments-projects.webp",[429,1829,1830,1831,1834],{},"Hiện tại, dự án phải được tạo thông qua công cụ ",[645,1832,1833],{},"buzz-cli"," (tuy nhiên tính năng tạo dự án trực tiếp trên giao diện người dùng đang được lên kế hoạch cho phiên bản tiếp theo).",[586,1836,1838],{"id":1837},"cài-đặt-buzz-cli","Cài đặt buzz-cli",[429,1840,1841,1842,1844,1845,1276],{},"Chạy các lệnh sau để cài đặt ",[645,1843,1833],{}," trên máy chủ ",[442,1846,1676],{},[665,1848,1850],{"className":667,"code":1849,"language":669,"meta":424,"style":424},"sudo apt install cargo\ncd ~\u002Fbuzz\ncargo install --path crates\u002Fbuzz-cli\necho 'export PATH=\"$HOME\u002F.cargo\u002Fbin:$PATH\"' >> ~\u002F.bashrc && source ~\u002F.bashrc\n",[645,1851,1852,1863,1870,1883],{"__ignoreMap":424},[673,1853,1854,1856,1858,1860],{"class":675,"line":676},[673,1855,841],{"class":679},[673,1857,844],{"class":687},[673,1859,868],{"class":687},[673,1861,1862],{"class":687}," cargo\n",[673,1864,1865,1867],{"class":675,"line":741},[673,1866,996],{"class":785},[673,1868,1869],{"class":687}," ~\u002Fbuzz\n",[673,1871,1872,1875,1877,1880],{"class":675,"line":614},[673,1873,1874],{"class":679},"cargo",[673,1876,868],{"class":687},[673,1878,1879],{"class":687}," --path",[673,1881,1882],{"class":687}," crates\u002Fbuzz-cli\n",[673,1884,1885,1887,1890,1893,1896,1899,1902,1905,1908],{"class":675,"line":776},[673,1886,786],{"class":785},[673,1888,1889],{"class":683}," '",[673,1891,1892],{"class":687},"export PATH=\"$HOME\u002F.cargo\u002Fbin:$PATH\"",[673,1894,1895],{"class":683},"'",[673,1897,1898],{"class":683}," >>",[673,1900,1901],{"class":687}," ~\u002F.bashrc",[673,1903,1904],{"class":683}," &&",[673,1906,1907],{"class":785}," source",[673,1909,1910],{"class":687}," ~\u002F.bashrc\n",[429,1912,1913,1914,1916,1917,1919],{},"Tạo một cặp khóa riêng tư và khóa công khai bằng công cụ trực tuyến hoặc thông qua ",[645,1915,1833],{},". Cặp khóa này là danh tính đại diện của ",[645,1918,1833],{}," trên Nostr relay.",[665,1921,1923],{"className":667,"code":1922,"language":669,"meta":424,"style":424},"docker run --rm --entrypoint \u002Fusr\u002Flocal\u002Fbin\u002Fbuzz-admin ghcr.io\u002Fblock\u002Fbuzz:main generate-key\n\n# Use the generated Public Key\ndocker compose exec relay buzz-admin add-member --pubkey generated_Public_key\n",[645,1924,1925,1947,1951,1956],{"__ignoreMap":424},[673,1926,1927,1929,1932,1935,1938,1941,1944],{"class":675,"line":676},[673,1928,922],{"class":679},[673,1930,1931],{"class":687}," run",[673,1933,1934],{"class":687}," --rm",[673,1936,1937],{"class":687}," --entrypoint",[673,1939,1940],{"class":687}," \u002Fusr\u002Flocal\u002Fbin\u002Fbuzz-admin",[673,1942,1943],{"class":687}," ghcr.io\u002Fblock\u002Fbuzz:main",[673,1945,1946],{"class":687}," generate-key\n",[673,1948,1949],{"class":675,"line":741},[673,1950,773],{"emptyLinePlaceholder":772},[673,1952,1953],{"class":675,"line":614},[673,1954,1955],{"class":737},"# Use the generated Public Key\n",[673,1957,1958,1960,1962,1964,1966,1968,1970,1972],{"class":675,"line":776},[673,1959,922],{"class":679},[673,1961,964],{"class":687},[673,1963,1691],{"class":687},[673,1965,1694],{"class":687},[673,1967,1697],{"class":687},[673,1969,1700],{"class":687},[673,1971,1703],{"class":687},[673,1973,1974],{"class":687}," generated_Public_key\n",[429,1976,1977],{},"Cấu hình giao diện dòng lệnh (CLI):",[665,1979,1981],{"className":667,"code":1980,"language":669,"meta":424,"style":424},"# Copy the Secret key as the BUZZ_PRIVATE_KEY\necho 'export BUZZ_PRIVATE_KEY=\"nsec1...\"'  >> \u002Fhome\u002F\u003Cuser>\u002F.bashrc\n\necho 'export BUZZ_RELAY_URL=\"wss:\u002F\u002Fbuzz.pafor.me\"'  >> \u002Fhome\u002F\u003Cuser>\u002F.bashrc\n",[645,1982,1983,1988,2021,2025],{"__ignoreMap":424},[673,1984,1985],{"class":675,"line":676},[673,1986,1987],{"class":737},"# Copy the Secret key as the BUZZ_PRIVATE_KEY\n",[673,1989,1990,1992,1994,1997,1999,2002,2005,2008,2011,2015,2018],{"class":675,"line":741},[673,1991,786],{"class":785},[673,1993,1889],{"class":683},[673,1995,1996],{"class":687},"export BUZZ_PRIVATE_KEY=\"nsec1...\"",[673,1998,1895],{"class":683},[673,2000,2001],{"class":683},"  >>",[673,2003,2004],{"class":687}," \u002Fhome\u002F",[673,2006,2007],{"class":683},"\u003C",[673,2009,2010],{"class":687},"use",[673,2012,2014],{"class":2013},"sTEyZ","r",[673,2016,2017],{"class":683},">",[673,2019,2020],{"class":687},"\u002F.bashrc\n",[673,2022,2023],{"class":675,"line":614},[673,2024,773],{"emptyLinePlaceholder":772},[673,2026,2027,2029,2031,2034,2036,2038,2040,2042,2044,2046,2048],{"class":675,"line":776},[673,2028,786],{"class":785},[673,2030,1889],{"class":683},[673,2032,2033],{"class":687},"export BUZZ_RELAY_URL=\"wss:\u002F\u002Fbuzz.pafor.me\"",[673,2035,1895],{"class":683},[673,2037,2001],{"class":683},[673,2039,2004],{"class":687},[673,2041,2007],{"class":683},[673,2043,2010],{"class":687},[673,2045,2014],{"class":2013},[673,2047,2017],{"class":683},[673,2049,2020],{"class":687},[429,2051,2052,2053,2055],{},"Chạy lệnh sau để xác minh rằng ",[645,2054,1833],{}," đã được cấu hình chính xác:",[665,2057,2059],{"className":667,"code":2058,"language":669,"meta":424,"style":424},"buzz channels list\n",[645,2060,2061],{"__ignoreMap":424},[673,2062,2063,2066,2069],{"class":675,"line":676},[673,2064,2065],{"class":679},"buzz",[673,2067,2068],{"class":687}," channels",[673,2070,2071],{"class":687}," list\n",[429,2073,2074],{},[435,2075],{"alt":2076,"src":2077},"Thực thi lệnh terminal xác minh cấu hình buzz-cli bằng cách liệt kê các kênh đang hoạt động","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-cli-channels-list-terminal.webp",[586,2079,2081],{"id":2080},"tạo-một-dự-án-bằng-buzz-cli","Tạo một dự án bằng buzz-cli",[665,2083,2085],{"className":667,"code":2084,"language":669,"meta":424,"style":424},"# --channel refers to the UUID of the channel\nbuzz repos create --id TestKOA --name 'Display Name' --channel \"bd92b3d1-8fac-441c-a9ac-2b2f3aac5c5b\"\n",[645,2086,2087,2092],{"__ignoreMap":424},[673,2088,2089],{"class":675,"line":676},[673,2090,2091],{"class":737},"# --channel refers to the UUID of the channel\n",[673,2093,2094,2096,2099,2102,2105,2108,2111,2113,2116,2118,2121,2123,2126],{"class":675,"line":741},[673,2095,2065],{"class":679},[673,2097,2098],{"class":687}," repos",[673,2100,2101],{"class":687}," create",[673,2103,2104],{"class":687}," --id",[673,2106,2107],{"class":687}," TestKOA",[673,2109,2110],{"class":687}," --name",[673,2112,1889],{"class":683},[673,2114,2115],{"class":687},"Display Name",[673,2117,1895],{"class":683},[673,2119,2120],{"class":687}," --channel",[673,2122,684],{"class":683},[673,2124,2125],{"class":687},"bd92b3d1-8fac-441c-a9ac-2b2f3aac5c5b",[673,2127,702],{"class":683},[429,2129,2130,2131,2133],{},"Một dự án chỉ có thể xóa bởi chủ sở hữu. Do dự án \"Display Name\" được tạo bằng ",[645,2132,1833],{}," (vốn chưa hỗ trợ lệnh xóa), nó sẽ không thể xóa theo cách này.",[429,2135,2136],{},"Mở lại ứng dụng Buzz trên máy tính để kiểm tra xem dự án đã được tạo thành công hay chưa.",[429,2138,2139],{},[435,2140],{"alt":2141,"src":2142},"Chế độ xem dự án trên ứng dụng Buzz máy tính xác nhận việc tạo dự án thành công","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-project-view.webp",[429,2144,2145],{},"Khi dự án xuất hiện trong phần Projects, bạn có thể dễ dàng thêm nhiều dự án khác bằng cách nhấn nút \"+\" ở góc trên bên phải.",[429,2147,2148],{},[435,2149],{"alt":2150,"src":2151},"Thêm dự án nhà phát triển mới bằng biểu tượng dấu cộng trong ứng dụng khách Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-add-project-button.webp",[586,2153,2155],{"id":2154},"đưa-vào-các-kho-lưu-trữ-git-hiện-có","Đưa vào các kho lưu trữ Git hiện có",[429,2157,2158,2159,2162,2163,2166,2167,2172],{},"Cài đặt ",[645,2160,2161],{},"git-credential-nostr"," trên thiết bị chứa các kho Git của bạn. Công cụ này yêu cầu ",[442,2164,2165],{},"git phiên bản 2.46 trở lên"," và bộ công cụ Rust. Hãy tham khảo tài liệu hướng dẫn ",[569,2168,2171],{"href":2169,"rel":2170},"https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz\u002Ftree\u002Fmain\u002Fcrates\u002Fgit-credential-nostr",[1654],"Readme"," này:",[665,2174,2176],{"className":667,"code":2175,"language":669,"meta":424,"style":424},"cargo install --path crates\u002Fgit-credential-nostr\n",[645,2177,2178],{"__ignoreMap":424},[673,2179,2180,2182,2184,2186],{"class":675,"line":676},[673,2181,1874],{"class":679},[673,2183,868],{"class":687},[673,2185,1879],{"class":687},[673,2187,2188],{"class":687}," crates\u002Fgit-credential-nostr\n",[429,2190,2191,2192,2194],{},"Siết chặt cơ chế bảo mật bằng cách cấu hình ",[645,2193,2161],{}," để cấp quyền truy cập qua Buzz relay:",[665,2196,2198],{"className":667,"code":2197,"language":669,"meta":424,"style":424},"# 1. Register the helper and enable per-path credentials.\ngit config --global credential.helper nostr\ngit config --global credential.useHttpPath true\n\n# 2. Store your nsec in a key file (must be 0600). Replace \"nsec1...\" with your private key\nmkdir -p ~\u002F.nostr\necho \"nsec1...\" > ~\u002F.nostr\u002Fkey && chmod 600 ~\u002F.nostr\u002Fkey\ngit config --global nostr.keyfile ~\u002F.nostr\u002Fkey\n",[645,2199,2200,2205,2221,2235,2239,2244,2253,2280],{"__ignoreMap":424},[673,2201,2202],{"class":675,"line":676},[673,2203,2204],{"class":737},"# 1. Register the helper and enable per-path credentials.\n",[673,2206,2207,2209,2212,2215,2218],{"class":675,"line":741},[673,2208,981],{"class":679},[673,2210,2211],{"class":687}," config",[673,2213,2214],{"class":687}," --global",[673,2216,2217],{"class":687}," credential.helper",[673,2219,2220],{"class":687}," nostr\n",[673,2222,2223,2225,2227,2229,2232],{"class":675,"line":614},[673,2224,981],{"class":679},[673,2226,2211],{"class":687},[673,2228,2214],{"class":687},[673,2230,2231],{"class":687}," credential.useHttpPath",[673,2233,2234],{"class":683}," true\n",[673,2236,2237],{"class":675,"line":776},[673,2238,773],{"emptyLinePlaceholder":772},[673,2240,2241],{"class":675,"line":782},[673,2242,2243],{"class":737},"# 2. Store your nsec in a key file (must be 0600). Replace \"nsec1...\" with your private key\n",[673,2245,2246,2248,2250],{"class":675,"line":827},[673,2247,1613],{"class":679},[673,2249,1616],{"class":687},[673,2251,2252],{"class":687}," ~\u002F.nostr\n",[673,2254,2255,2257,2259,2262,2264,2266,2269,2271,2274,2277],{"class":675,"line":832},[673,2256,786],{"class":785},[673,2258,684],{"class":683},[673,2260,2261],{"class":687},"nsec1...",[673,2263,691],{"class":683},[673,2265,821],{"class":683},[673,2267,2268],{"class":687}," ~\u002F.nostr\u002Fkey",[673,2270,1904],{"class":683},[673,2272,2273],{"class":679}," chmod",[673,2275,2276],{"class":1311}," 600",[673,2278,2279],{"class":687}," ~\u002F.nostr\u002Fkey\n",[673,2281,2282,2284,2286,2288,2291],{"class":675,"line":838},[673,2283,981],{"class":679},[673,2285,2211],{"class":687},[673,2287,2214],{"class":687},[673,2289,2290],{"class":687}," nostr.keyfile",[673,2292,2279],{"class":687},[429,2294,2295],{},"Tạo một kho lưu trữ mới trên Buzz relay:",[665,2297,2300],{"className":2298,"code":2299,"language":1037},[1035],"buzz repos create --id koa-email-routing --name \"KOA Email Routing\" --clone \"https:\u002F\u002Fbuzz.pafor.me\u002Fgit\u002F\u003Cpub_key>\u002Fkoa-email-routing\" --nostr-relay \"wss:\u002F\u002Fbuzz.pafor.me\"\n",[645,2301,2299],{"__ignoreMap":424},[429,2303,2304,2305,2308,2309,2312],{},"Trong lần ",[645,2306,2307],{},"git push"," đầu tiên, bạn sẽ gặp lỗi ",[645,2310,2311],{},"remote: missing Authorization header",". Để giải quyết lỗi này, bạn cần liên kết ID kho lưu trữ với một kênh của Buzz, vì quyền ghi Git (ACL) được quản lý dựa trên danh sách thành viên của kênh:",[665,2314,2316],{"className":667,"code":2315,"language":669,"meta":424,"style":424},"buzz repos bind --id koa-email-routing --channel \u003CCHANNEL_UUID>\n\n# push the code again\ngit push\n",[645,2317,2318,2346,2350,2355],{"__ignoreMap":424},[673,2319,2320,2322,2324,2327,2329,2332,2334,2337,2340,2343],{"class":675,"line":676},[673,2321,2065],{"class":679},[673,2323,2098],{"class":687},[673,2325,2326],{"class":687}," bind",[673,2328,2104],{"class":687},[673,2330,2331],{"class":687}," koa-email-routing",[673,2333,2120],{"class":687},[673,2335,2336],{"class":683}," \u003C",[673,2338,2339],{"class":687},"CHANNEL_UUI",[673,2341,2342],{"class":2013},"D",[673,2344,2345],{"class":683},">\n",[673,2347,2348],{"class":675,"line":741},[673,2349,773],{"emptyLinePlaceholder":772},[673,2351,2352],{"class":675,"line":614},[673,2353,2354],{"class":737},"# push the code again\n",[673,2356,2357,2359],{"class":675,"line":776},[673,2358,981],{"class":679},[673,2360,2361],{"class":687}," push\n",[429,2363,2364,2365,2368],{},"Khi kiểm tra dự án trên ứng dụng Buzz máy tính, bạn có thể thấy lỗi hiển thị do ứng dụng yêu cầu ",[442,2366,2367],{},"git 2.46 trở lên"," — việc khởi chạy trực tiếp ứng dụng đôi khi nhận diện sai phiên bản Git cũ hơn hệ thống:",[429,2370,2371],{},[435,2372],{"alt":2373,"src":2374},"Ứng dụng khách Buzz hiển thị lỗi tải Git do phiên bản Git cục bộ cũ dưới 2.46","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-git-version-error.webp",[429,2376,2377,2378,2381,2382,2387],{},"Hãy xuất biến PATH bằng lệnh ",[645,2379,2380],{},"launchctl setenv PATH \"\u002Fopt\u002Fhomebrew\u002Fbin:\u002Fusr\u002Flocal\u002Fbin:\u002Fusr\u002Fbin:\u002Fbin:\u002Fusr\u002Fsbin:\u002Fsbin\""," trong cấu hình shell của bạn và khởi động ứng dụng Buzz trực tiếp từ terminal. Tham khảo ",[569,2383,2386],{"href":2384,"rel":2385},"https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz\u002Fissues\u002F5348",[1654],"lỗi này"," để biết thêm chi tiết.",[665,2389,2391],{"className":667,"code":2390,"language":669,"meta":424,"style":424},"open -a Buzz\n",[645,2392,2393],{"__ignoreMap":424},[673,2394,2395,2398,2401],{"class":675,"line":676},[673,2396,2397],{"class":679},"open",[673,2399,2400],{"class":687}," -a",[673,2402,2403],{"class":687}," Buzz\n",[429,2405,2406],{},"Kiểm tra lại mục Projects trên ứng dụng Buzz, thông tin chi tiết của kho lưu trữ hiện đã được tải lên đầy đủ.",[429,2408,2409],{},[435,2410],{"alt":2411,"src":2412},"Giao diện Buzz máy tính với thông tin chi tiết về kho lưu trữ Git và nhật ký commit đã tải thành công","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-repository-details-loaded.webp",[447,2414,2416],{"id":2415},"đồng-bộ-hóa-các-tác-nhân-ai-với-ứng-dụng-di-động-buzz-bằng-mã-qr","Đồng bộ hóa các tác nhân AI với ứng dụng di động Buzz bằng mã QR",[429,2418,2419,2420,2423],{},"Việc ghép đôi với ứng dụng di động Buzz yêu cầu giao thức HTTPS bảo mật và dịch vụ ",[645,2421,2422],{},"buzz-pair-relay"," mặc định sẽ không khởi chạy trên VPS.",[665,2425,2427],{"className":667,"code":2426,"language":669,"meta":424,"style":424},"cd ~\u002Fbuzz\ncargo install --path crates\u002Fbuzz-pair-relay\n",[645,2428,2429,2435],{"__ignoreMap":424},[673,2430,2431,2433],{"class":675,"line":676},[673,2432,996],{"class":785},[673,2434,1869],{"class":687},[673,2436,2437,2439,2441,2443],{"class":675,"line":741},[673,2438,1874],{"class":679},[673,2440,868],{"class":687},[673,2442,1879],{"class":687},[673,2444,2445],{"class":687}," crates\u002Fbuzz-pair-relay\n",[429,2447,2448,2449,2452,2453,1276],{},"Thêm khối cấu hình sau vào tệp ",[645,2450,2451],{},"compose.yml"," để kích hoạt dịch vụ ",[645,2454,2422],{},[665,2456,2458],{"className":1164,"code":2457,"language":1166,"meta":424,"style":424},"  pair:\n    image: ${BUZZ_IMAGE:-ghcr.io\u002Fblock\u002Fbuzz:main}\n    entrypoint: [\"\u002Fusr\u002Flocal\u002Fbin\u002Fbuzz-pair-relay\"]\n    environment:\n      BUZZ_PAIR_RELAY_BIND_ADDR: 0.0.0.0:5000\n    ports:\n      - \"${BUZZ_PAIR_RELAY_PORT:-5000}:5000\"\n    restart: unless-stopped\n    networks:\n      [buzz-net]\n",[645,2459,2460,2467,2476,2496,2502,2512,2518,2529,2537,2543],{"__ignoreMap":424},[673,2461,2462,2465],{"class":675,"line":676},[673,2463,2464],{"class":1257},"  pair",[673,2466,1261],{"class":683},[673,2468,2469,2471,2473],{"class":675,"line":741},[673,2470,1327],{"class":1257},[673,2472,1276],{"class":683},[673,2474,2475],{"class":687}," ${BUZZ_IMAGE:-ghcr.io\u002Fblock\u002Fbuzz:main}\n",[673,2477,2478,2481,2483,2486,2488,2491,2493],{"class":675,"line":614},[673,2479,2480],{"class":1257},"    entrypoint",[673,2482,1276],{"class":683},[673,2484,2485],{"class":683}," [",[673,2487,691],{"class":683},[673,2489,2490],{"class":687},"\u002Fusr\u002Flocal\u002Fbin\u002Fbuzz-pair-relay",[673,2492,691],{"class":683},[673,2494,2495],{"class":683},"]\n",[673,2497,2498,2500],{"class":675,"line":776},[673,2499,1361],{"class":1257},[673,2501,1261],{"class":683},[673,2503,2504,2507,2509],{"class":675,"line":782},[673,2505,2506],{"class":1257},"      BUZZ_PAIR_RELAY_BIND_ADDR",[673,2508,1276],{"class":683},[673,2510,2511],{"class":687}," 0.0.0.0:5000\n",[673,2513,2514,2516],{"class":675,"line":827},[673,2515,1273],{"class":1257},[673,2517,1261],{"class":683},[673,2519,2520,2522,2524,2527],{"class":675,"line":832},[673,2521,1394],{"class":683},[673,2523,684],{"class":683},[673,2525,2526],{"class":687},"${BUZZ_PAIR_RELAY_PORT:-5000}:5000",[673,2528,702],{"class":683},[673,2530,2531,2533,2535],{"class":675,"line":838},[673,2532,1446],{"class":1257},[673,2534,1276],{"class":683},[673,2536,1451],{"class":687},[673,2538,2539,2541],{"class":675,"line":850},[673,2540,1457],{"class":1257},[673,2542,1261],{"class":683},[673,2544,2545,2548,2551],{"class":675,"line":855},[673,2546,2547],{"class":683},"      [",[673,2549,2550],{"class":687},"buzz-net",[673,2552,2495],{"class":683},[429,2554,2555,2556,2559,2560,2563,2564,1276],{},"Thêm ",[645,2557,2558],{},"BUZZ_PAIRING_RELAY_URL"," và ",[645,2561,2562],{},"BUZZ_PAIR_RELAY_PORT"," vào tệp cấu hình ",[645,2565,1023],{},[665,2567,2570],{"className":2568,"code":2569,"language":1037},[1035],"BUZZ_PAIRING_RELAY_URL=wss:\u002F\u002Fbuzz.pafor.me\u002Fpair\nBUZZ_PAIR_RELAY_PORT=5000\n",[645,2571,2569],{"__ignoreMap":424},[429,2573,2574,2575,2578],{},"Truy cập mục '",[442,2576,2577],{},"Mobile","' trong phần cài đặt của Buzz desktop:",[429,2580,2581],{},[435,2582],{"alt":2583,"src":2584},"Hộp thoại cài đặt trong ứng dụng Buzz hiển thị tab cấu hình thiết bị di động","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-settings-mobile-tab.webp",[429,2586,2587],{},"Nhấp vào \"Start pairing\" — một mã QR sẽ hiển thị; hãy dùng ứng dụng Buzz trên điện thoại để quét mã này. Quá trình ghép đôi hoàn tất sau khi bạn nhấn \"Code Match\".",[429,2589,2590],{},[435,2591],{"alt":2592,"src":2593},"Tạo mã QR ghép đôi an toàn trên ứng dụng máy tính để đồng bộ hóa di động Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-pairing-qr-code.webp",[429,2595,2596],{},"Các tác nhân AI trên ứng dụng di động Buzz chỉ có thể sử dụng nếu chúng đang chạy đồng thời trên ứng dụng Buzz máy tính. Thiết bị máy tính của bạn phải luôn hoạt động để các tác nhân AI có thể xử lý yêu cầu.",[429,2598,2599],{},[435,2600],{"alt":2601,"src":2602},"Giao diện ứng dụng di động Buzz hiển thị các tác nhân AI đồng hành hoạt động đã đồng bộ","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-mobile-app-active-agents.webp",[447,2604,2606],{"id":2605},"lời-kết","Lời kết",[429,2608,2609],{},"Mặc dù Buzz vẫn còn quá sớm để áp dụng vào các môi trường sản xuất quy mô lớn do tồn tại một số lỗi và giới hạn về giao diện, đây thực sự là một trải nghiệm đột phá cho các đội nhóm nhỏ và các nhà phát triển độc lập. Nó mở ra một tầm nhìn chân thực về không gian làm việc ưu tiên AI và mang tính cộng tác cao trong tương lai.",[447,2611,2613],{"id":2612},"tài-liệu-tham-khảo","Tài liệu tham khảo",[455,2615,2616,2623,2630,2637],{},[458,2617,2618],{},[569,2619,2622],{"href":2620,"rel":2621},"https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz",[1654],"Buzz releases",[458,2624,2625],{},[569,2626,2629],{"href":2627,"rel":2628},"https:\u002F\u002Fblock.xyz\u002Finside\u002Fintroducing-buzz-where-humans-and-agents-work-together",[1654],"Introducing Buzz",[458,2631,2632],{},[569,2633,2636],{"href":2634,"rel":2635},"https:\u002F\u002Fwww.hostinger.com\u002Ftutorials\u002Fwhat-is-buzz",[1654],"What is buzz",[458,2638,2639],{},[569,2640,2643],{"href":2641,"rel":2642},"https:\u002F\u002Fmiget.com\u002Fblog\u002Fhow-to-self-host-buzz",[1654],"How to self-host Buzz (Miget)",[2645,2646,2647],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":424,"searchDepth":741,"depth":614,"links":2649},[2650,2651,2652,2666,2675,2676,2677],{"id":449,"depth":741,"text":450},{"id":496,"depth":741,"text":497},{"id":544,"depth":741,"text":545,"children":2653},[2654,2655,2659,2660,2661,2665],{"id":549,"depth":614,"text":550},{"id":583,"depth":614,"text":584,"children":2656},[2657,2658],{"id":588,"depth":776,"text":589},{"id":705,"depth":776,"text":706},{"id":723,"depth":614,"text":724},{"id":970,"depth":614,"text":971},{"id":1129,"depth":614,"text":1130,"children":2662},[2663,2664],{"id":1133,"depth":776,"text":1134},{"id":1535,"depth":776,"text":1536},{"id":1602,"depth":614,"text":1603},{"id":1645,"depth":741,"text":1646,"children":2667},[2668,2669,2670],{"id":1731,"depth":614,"text":1732},{"id":1776,"depth":614,"text":1777},{"id":1813,"depth":614,"text":1814,"children":2671},[2672,2673,2674],{"id":1837,"depth":776,"text":1838},{"id":2080,"depth":776,"text":2081},{"id":2154,"depth":776,"text":2155},{"id":2415,"depth":741,"text":2416},{"id":2605,"depth":741,"text":2606},{"id":2612,"depth":741,"text":2613},[2679,2680,2065],"collaboration","ai-agents","2026-09-08","Tìm hiểu cách tự host Block's Buzz trên VPS Linux phía sau Cloudflare. Vận hành không gian làm việc Nostr bảo mật giúp con người và AI cộng tác hiệu quả.","md","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002FVI-Self-Hosting-Buzz-As-The-Workspace-Where-AI-Agents-Become-Colleagues.webp","Một thẻ công nghệ 16:9 cao cấp với các điểm nhấn màu xanh đậm và màu cam minh họa cách tự lưu trữ (self-host) cổng relay Buzz của Block trên Ubuntu VPS, có bảng glassmorphic sạch sẽ với kiểu chữ chính giữa.",{"schemaOrg":2687,"robots":2709,"sitemap":2710},[2688,2690],{"@type":2689,"headline":423,"description":2682,"image":2684},"TechArticle",{"@type":2691,"name":423,"description":2682,"image":2684,"step":2692},"HowTo",[2693,2697,2700,2703,2706],{"@type":2694,"name":2695,"text":2696},"HowToStep","Giai đoạn 1: Thiết lập Cloudflare","Tạo API Token Cloudflare và định cấu hình cài đặt DNS.",{"@type":2694,"name":2698,"text":2699},"Giai đoạn 2: Cài đặt Docker","Thiết lập và cài đặt Docker Engine trên VPS Ubuntu.",{"@type":2694,"name":2701,"text":2702},"Giai đoạn 3: Nhân bản và Cấu hình","Nhân bản kho lưu trữ và định cấu hình các biến compose.",{"@type":2694,"name":2704,"text":2705},"Giai đoạn 4: Tích hợp Caddy","Xây dựng Caddy tùy chỉnh với mô-đun thử thách DNS Cloudflare.",{"@type":2694,"name":2707,"text":2708},"Giai đoạn 5: Sao lưu tự động","Định cấu hình cron job để tự động sao lưu PostgreSQL.","index, follow",{"lastmod":2711},"2026-09-03",{"title":2713,"description":2682,"ogTitle":423,"ogDescription":2682,"twitterTitle":423,"twitterDescription":2682},"Hướng dẫn tự host Block Buzz Relay trên VPS Ubuntu","vi\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues",[2716,2717,444,2718,2719],"Nostr","Docker","Caddy","Cloudflare",null,"4n6TAwckx54GT3WMA-sqwXdGcmS8qZxFUgRYb8qCjWk",{"surround":2723,"related":6025},[2724,4623],{"id":2725,"title":2726,"author":2720,"body":2727,"category":4605,"date":4607,"description":4608,"extension":2683,"image":4609,"imageAlt":4610,"isPublished":772,"meta":4611,"minRead":1510,"navigation":772,"path":295,"seo":4618,"stem":4619,"tags":4620,"updatedAt":2711,"__hash__":4622},"article\u002Fvi\u002Farticle\u002Fself-hosted-travel-planner-trek.md","Tự host kế hoạch du lịch của bạn với TREK và Docker",{"type":426,"value":2728,"toc":4564},[2729,2732,2735,2738,2742,2746,2888,2892,2898,2917,2920,2924,3028,3039,3042,3047,3050,3061,3065,3069,3072,3075,3115,3119,3122,3154,3157,3197,3200,3205,3216,3220,3227,3231,3234,3328,3332,3338,3342,3349,3353,3356,3374,3384,3388,3391,3401,3405,3409,3418,3422,3426,3429,3433,3437,3440,3445,3448,3453,3459,3463,3467,3470,3474,3488,3493,3499,3504,3508,3511,3516,3521,3524,3531,3535,3538,3541,3551,3558,3563,3569,3574,3578,3583,3588,3591,3596,3600,3606,3610,3615,3619,3622,3625,3630,3635,3640,3644,3651,3656,3661,3666,3671,3675,3680,3685,3691,3695,3698,3702,3708,3713,3718,3724,3729,3734,3739,3753,3757,3762,3783,3788,3791,3795,3798,3803,3806,3853,3857,3864,3870,3875,3881,3886,3892,3897,3903,3906,3911,3917,3922,3928,3932,3938,3943,3948,3952,3956,3959,3963,3966,3973,3977,3984,3988,4000,4005,4009,4013,4023,4033,4038,4045,4050,4057,4061,4064,4228,4234,4238,4241,4246,4249,4255,4259,4266,4270,4273,4278,4285,4290,4294,4304,4375,4391,4394,4399,4403,4407,4417,4494,4504,4507,4511,4515,4518,4520,4523,4526,4535,4538,4561],[429,2730,2731],{},"Phần tẻ nhạt nhất của việc lập kế hoạch du lịch là các tệp PDF đặt vé máy bay, xác nhận khách sạn, các cuộc trò chuyện với bạn đồng hành và danh sách các địa điểm muốn ghé thăm thường bị rải rác ở nhiều nơi khác nhau. Khi đến lúc tính toán tổng chi tiêu và chia hóa đơn, bạn sẽ phải tốn rất nhiều công sức để lục lọi lại toàn bộ đống dữ liệu du lịch đó.",[429,2733,2734],{},"TREK là một công cụ lập kế hoạch du lịch mã nguồn mở có thể tự lưu trữ (self-host), giúp gom toàn bộ lịch trình, thông tin đặt chỗ, ngân sách và danh sách đồ dùng cần mang theo vào một nơi duy nhất. Server MCP tích hợp sẵn cho phép các tác nhân AI (chẳng hạn như Claude Desktop) thao tác trực tiếp với dữ liệu du lịch của bạn.",[429,2736,2737],{},"Hướng dẫn này sẽ đi cùng bạn qua mọi bước, từ triển khai cài đặt đến việc quản lý hoàn chỉnh một chuyến đi thực tế từ đầu đến cuối.",[547,2739,2741],{"id":2740},"_1-cách-triển-khai-công-cụ-lập-kế-hoạch-du-lịch-trek-bằng-docker","1. Cách triển khai công cụ lập kế hoạch du lịch TREK bằng Docker",[586,2743,2745],{"id":2744},"cài-đặt-docker-trên-vps-ubuntu","Cài đặt Docker trên VPS Ubuntu",[665,2747,2749],{"className":667,"code":2748,"language":669,"meta":424,"style":424},"# Add Docker's official GPG key and set up the Docker repository\ncurl -fsSL https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu\u002Fgpg | sudo gpg --dearmor -o \u002Fusr\u002Fshare\u002Fkeyrings\u002Fdocker-archive-keyring.gpg\n\n# Add the official Docker repository\necho \"deb [arch=amd64 signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fdocker-archive-keyring.gpg] https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu $(lsb_release -cs) stable\" | sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.list > \u002Fdev\u002Fnull\n\n# Update package list\nsudo apt update\n\n# Install Docker Engine, Docker Community Edition, and containerd runtime\nsudo apt install docker-ce docker-ce-cli containerd.io -y\n\n# Verify docker is installed\ndocker --version\n\n# Starts automatically when your system boots\nsudo systemctl enable docker\n",[645,2750,2751,2755,2775,2779,2783,2815,2819,2823,2831,2835,2839,2855,2859,2863,2869,2873,2878],{"__ignoreMap":424},[673,2752,2753],{"class":675,"line":676},[673,2754,738],{"class":737},[673,2756,2757,2759,2761,2763,2765,2767,2769,2771,2773],{"class":675,"line":741},[673,2758,680],{"class":679},[673,2760,746],{"class":687},[673,2762,749],{"class":687},[673,2764,752],{"class":683},[673,2766,755],{"class":679},[673,2768,758],{"class":687},[673,2770,761],{"class":687},[673,2772,764],{"class":687},[673,2774,767],{"class":687},[673,2776,2777],{"class":675,"line":614},[673,2778,773],{"emptyLinePlaceholder":772},[673,2780,2781],{"class":675,"line":776},[673,2782,779],{"class":737},[673,2784,2785,2787,2789,2791,2793,2795,2797,2799,2801,2803,2805,2807,2809,2811,2813],{"class":675,"line":782},[673,2786,786],{"class":785},[673,2788,684],{"class":683},[673,2790,791],{"class":687},[673,2792,794],{"class":683},[673,2794,797],{"class":679},[673,2796,800],{"class":687},[673,2798,803],{"class":683},[673,2800,806],{"class":687},[673,2802,691],{"class":683},[673,2804,752],{"class":683},[673,2806,755],{"class":679},[673,2808,815],{"class":687},[673,2810,818],{"class":687},[673,2812,821],{"class":683},[673,2814,824],{"class":687},[673,2816,2817],{"class":675,"line":827},[673,2818,773],{"emptyLinePlaceholder":772},[673,2820,2821],{"class":675,"line":832},[673,2822,835],{"class":737},[673,2824,2825,2827,2829],{"class":675,"line":838},[673,2826,841],{"class":679},[673,2828,844],{"class":687},[673,2830,847],{"class":687},[673,2832,2833],{"class":675,"line":850},[673,2834,773],{"emptyLinePlaceholder":772},[673,2836,2837],{"class":675,"line":855},[673,2838,858],{"class":737},[673,2840,2841,2843,2845,2847,2849,2851,2853],{"class":675,"line":861},[673,2842,841],{"class":679},[673,2844,844],{"class":687},[673,2846,868],{"class":687},[673,2848,871],{"class":687},[673,2850,874],{"class":687},[673,2852,877],{"class":687},[673,2854,880],{"class":687},[673,2856,2857],{"class":675,"line":883},[673,2858,773],{"emptyLinePlaceholder":772},[673,2860,2861],{"class":675,"line":888},[673,2862,916],{"class":737},[673,2864,2865,2867],{"class":675,"line":894},[673,2866,922],{"class":679},[673,2868,925],{"class":687},[673,2870,2871],{"class":675,"line":908},[673,2872,773],{"emptyLinePlaceholder":772},[673,2874,2875],{"class":675,"line":913},[673,2876,2877],{"class":737},"# Starts automatically when your system boots\n",[673,2879,2880,2882,2884,2886],{"class":675,"line":919},[673,2881,841],{"class":679},[673,2883,899],{"class":687},[673,2885,902],{"class":687},[673,2887,905],{"class":687},[586,2889,2891],{"id":2890},"tạo-khóa-mã-hóa","Tạo khóa mã hóa",[429,2893,2894,2895,2897],{},"TREK sử dụng một khóa để mã hóa dữ liệu nhạy cảm. Hãy sử dụng lệnh sau hoặc ",[569,2896,1065],{"href":1064}," này để tạo khóa mã hóa:",[665,2899,2901],{"className":667,"code":2900,"language":669,"meta":424,"style":424},"openssl rand -hex 32\n",[645,2902,2903],{"__ignoreMap":424},[673,2904,2905,2908,2911,2914],{"class":675,"line":676},[673,2906,2907],{"class":679},"openssl",[673,2909,2910],{"class":687}," rand",[673,2912,2913],{"class":687}," -hex",[673,2915,2916],{"class":1311}," 32\n",[429,2918,2919],{},"Hãy lưu khóa này ở nơi an toàn; việc mất khóa đồng nghĩa với việc bạn sẽ mất quyền truy cập vào dữ liệu đã được mã hóa.",[586,2921,2923],{"id":2922},"khởi-chạy-container","Khởi chạy container",[665,2925,2927],{"className":667,"code":2926,"language":669,"meta":424,"style":424},"docker run -d \\\n  --name trek \\\n  -p 3000:3000 \\\n  -e ENCRYPTION_KEY=\"\u003Cgenerated_key>\" \\\n  -e APP_URL=\"https:\u002F\u002Ftrek.pafor.me\" \\\n  -v .\u002Fdata:\u002Fapp\u002Fdata \\\n  -v .\u002Fuploads:\u002Fapp\u002Fuploads \\\n  --restart unless-stopped \\\n  mauriceboe\u002Ftrek:latest\n",[645,2928,2929,2941,2951,2961,2978,2994,3004,3013,3023],{"__ignoreMap":424},[673,2930,2931,2933,2935,2938],{"class":675,"line":676},[673,2932,922],{"class":679},[673,2934,1931],{"class":687},[673,2936,2937],{"class":687}," -d",[673,2939,2940],{"class":2013}," \\\n",[673,2942,2943,2946,2949],{"class":675,"line":741},[673,2944,2945],{"class":687},"  --name",[673,2947,2948],{"class":687}," trek",[673,2950,2940],{"class":2013},[673,2952,2953,2956,2959],{"class":675,"line":614},[673,2954,2955],{"class":687},"  -p",[673,2957,2958],{"class":687}," 3000:3000",[673,2960,2940],{"class":2013},[673,2962,2963,2966,2969,2971,2974,2976],{"class":675,"line":776},[673,2964,2965],{"class":687},"  -e",[673,2967,2968],{"class":687}," ENCRYPTION_KEY=",[673,2970,691],{"class":683},[673,2972,2973],{"class":687},"\u003Cgenerated_key>",[673,2975,691],{"class":683},[673,2977,2940],{"class":2013},[673,2979,2980,2982,2985,2987,2990,2992],{"class":675,"line":782},[673,2981,2965],{"class":687},[673,2983,2984],{"class":687}," APP_URL=",[673,2986,691],{"class":683},[673,2988,2989],{"class":687},"https:\u002F\u002Ftrek.pafor.me",[673,2991,691],{"class":683},[673,2993,2940],{"class":2013},[673,2995,2996,2999,3002],{"class":675,"line":827},[673,2997,2998],{"class":687},"  -v",[673,3000,3001],{"class":687}," .\u002Fdata:\u002Fapp\u002Fdata",[673,3003,2940],{"class":2013},[673,3005,3006,3008,3011],{"class":675,"line":832},[673,3007,2998],{"class":687},[673,3009,3010],{"class":687}," .\u002Fuploads:\u002Fapp\u002Fuploads",[673,3012,2940],{"class":2013},[673,3014,3015,3018,3021],{"class":675,"line":838},[673,3016,3017],{"class":687},"  --restart",[673,3019,3020],{"class":687}," unless-stopped",[673,3022,2940],{"class":2013},[673,3024,3025],{"class":675,"line":850},[673,3026,3027],{"class":687},"  mauriceboe\u002Ftrek:latest\n",[455,3029,3030],{},[458,3031,3032,3038],{},[442,3033,3034,3037],{},[645,3035,3036],{},"APP_URL"," phải được định cấu hình chính xác"," — luồng khám phá OAuth của server MCP phụ thuộc vào biến này. Hãy thiết lập nó thành địa chỉ HTTPS công khai cuối cùng của bạn ngay từ đầu.",[429,3040,3041],{},"Lần chạy đầu tiên sẽ mất một khoảng thời gian để tải image về:",[435,3043],{"src":3044,"alt":3045,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-docker-pull-image.webp","Nhật ký docker pull và run cho TREK","max-width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3048,3049],{},"Xác nhận container đang hoạt động:",[665,3051,3053],{"className":667,"code":3052,"language":669,"meta":424,"style":424},"docker ps\n",[645,3054,3055],{"__ignoreMap":424},[673,3056,3057,3059],{"class":675,"line":676},[673,3058,922],{"class":679},[673,3060,1582],{"class":687},[435,3062],{"src":3063,"alt":3064,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-docker-ps-status.webp","Xác minh trạng thái container đang chạy qua docker ps",[547,3066,3068],{"id":3067},"_2-thiết-lập-định-tuyến-tên-miền-ssl-với-caddy-reverse-proxy","2. Thiết lập định tuyến tên miền & SSL với Caddy Reverse Proxy",[429,3070,3071],{},"Giao thức HTTPS là bắt buộc đối với passkey, và OAuth đối với MCP. Tên miền được lưu trữ trên Cloudflare, đi kèm với chứng chỉ SSL miễn phí và tính năng bảo vệ DDoS.",[429,3073,3074],{},"Caddy được thiết lập như một máy chủ reverse proxy bảo mật để trỏ về cổng 3000. Ví dụ về file cấu hình Caddyfile như sau:",[665,3076,3080],{"className":3077,"code":3078,"language":3079,"meta":424,"style":424},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{$TREK_DOMAIN} {\n  encode zstd gzip\n  reverse_proxy host.docker.internal:3000\n}\n","json",[645,3081,3082,3096,3101,3111],{"__ignoreMap":424},[673,3083,3084,3087,3090,3093],{"class":675,"line":676},[673,3085,3086],{"class":683},"{",[673,3088,3089],{"class":2013},"$TREK_DOMAIN",[673,3091,3092],{"class":683},"}",[673,3094,3095],{"class":683}," {\n",[673,3097,3098],{"class":675,"line":741},[673,3099,3100],{"class":2013},"  encode zstd gzip\n",[673,3102,3103,3106,3108],{"class":675,"line":614},[673,3104,3105],{"class":2013},"  reverse_proxy host.docker.internal",[673,3107,1276],{"class":683},[673,3109,3110],{"class":1311},"3000\n",[673,3112,3113],{"class":675,"line":776},[673,3114,1187],{"class":683},[547,3116,3118],{"id":3117},"_3-cấu-hình-ban-đầu-thiết-lập-quản-trị-viên-bảo-mật","3. Cấu hình ban đầu & Thiết lập quản trị viên bảo mật",[429,3120,3121],{},"Có hai cách để tạo tài khoản quản trị viên (admin):",[455,3123,3124,3135],{},[458,3125,3126,3134],{},[442,3127,3128,2559,3131],{},[645,3129,3130],{},"ADMIN_EMAIL",[645,3132,3133],{},"ADMIN_PASSWORD"," được thiết lập làm biến môi trường; các giá trị này sẽ được sử dụng trực tiếp.",[458,3136,3137,3138,3141,3142,3145,3146,3149,3150,3153],{},"TREK tự động tạo email ",[645,3139,3140],{},"admin@trek.local",", tên đăng nhập ",[645,3143,3144],{},"admin",", và một ",[442,3147,3148],{},"mật khẩu được tạo ngẫu nhiên in trong container log",". Chạy lệnh ",[645,3151,3152],{},"docker logs trek"," để lấy mật khẩu này.",[429,3155,3156],{},"Nếu không tìm thấy mật khẩu từ log, bạn có thể đặt lại bằng lệnh:",[665,3158,3160],{"className":667,"code":3159,"language":669,"meta":424,"style":424},"docker exec -it -e RESET_ADMIN_EMAIL=admin@trek.local -e RESET_ADMIN_PASSWORD='YourNewPassword' trek node server\u002Freset-admin.js\n",[645,3161,3162],{"__ignoreMap":424},[673,3163,3164,3166,3168,3171,3174,3177,3179,3182,3184,3187,3189,3191,3194],{"class":675,"line":676},[673,3165,922],{"class":679},[673,3167,1691],{"class":687},[673,3169,3170],{"class":687}," -it",[673,3172,3173],{"class":687}," -e",[673,3175,3176],{"class":687}," RESET_ADMIN_EMAIL=admin@trek.local",[673,3178,3173],{"class":687},[673,3180,3181],{"class":687}," RESET_ADMIN_PASSWORD=",[673,3183,1895],{"class":683},[673,3185,3186],{"class":687},"YourNewPassword",[673,3188,1895],{"class":683},[673,3190,2948],{"class":687},[673,3192,3193],{"class":687}," node",[673,3195,3196],{"class":687}," server\u002Freset-admin.js\n",[429,3198,3199],{},"Bạn sẽ được nhắc đổi mật khẩu trong lần đăng nhập đầu tiên.",[435,3201],{"src":3202,"alt":3203,"style":3204},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-initial-login-password-prompt.webp","Lời nhắc đăng nhập lần đầu và đặt lại mật khẩu quản trị viên","max-width: 215px; width:100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3206,602,3207,3210,3211],{},[442,3208,3209],{},"Admin"," và cập nhật địa chỉ email:",[435,3212],{"src":3213,"alt":3214,"style":3215},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-admin-email-update-panel.webp","Thiết lập email tùy chỉnh trong cài đặt quản trị viên của TREK","max-width: 700px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[586,3217,3219],{"id":3218},"_31-sao-lưu-backups","3.1 Sao lưu (Backups)",[429,3221,3222,3223],{},"Định cấu hình sao lưu tự động với chính sách lưu trữ (retention policy) trong bảng quản trị:\n",[435,3224],{"src":3225,"alt":3226,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-admin-backup-retention-policy.webp","Cấu hình lịch trình sao lưu tự động và quy tắc lưu trữ",[586,3228,3230],{"id":3229},"_32-lưu-trữ-các-tệp-đã-tải-lên-vào-cloudflare-r2","3.2 Lưu trữ các tệp đã tải lên vào Cloudflare R2",[429,3232,3233],{},"Lưu trữ các tệp đã tải lên, ảnh và bản sao lưu trong Cloudflare R2 giúp dung lượng đĩa của VPS luôn sạch sẽ và nhẹ nhàng. TREK hỗ trợ các backend tương thích S3, và Cloudflare R2 hoàn toàn phù hợp với điều này.",[591,3235,3236,3242,3255,3266,3277,3291,3302,3317],{},[458,3237,3238,3239,599],{},"Tạo một bucket R2 tên là ",[645,3240,3241],{},"trek",[458,3243,3244,3245,3248,3249,3250],{},"Trong phần ",[442,3246,3247],{},"Account Details",", tìm ID tài khoản của bạn:","\n  ",[435,3251],{"src":3252,"alt":3253,"style":3254},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fcloudflare-r2-account-details-id.webp","Tìm ID tài khoản Cloudflare trong cổng thông tin","max-width: 325px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[458,3256,3257,3258,1276,3249,3261],{},"Nhấp vào ",[442,3259,3260],{},"Manage API Tokens",[435,3262],{"src":3263,"alt":3264,"style":3265},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fcloudflare-r2-manage-api-tokens-button.webp","Màn hình Quản lý mã thông báo API của cổng thông tin Cloudflare","max-width: 282px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[458,3267,3257,3268,3271,3249,3272],{},[442,3269,3270],{},"Create Account API token"," với quyền đọc\u002Fghi (read\u002Fwrite) cho bucket:",[435,3273],{"src":3274,"alt":3275,"style":3276},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fcloudflare-r2-create-token-permissions.webp","Tạo mã thông báo truy cập R2 với quyền đọc và ghi","max-width: 360px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[458,3278,602,3279,3282,3283,1276,3249,3286],{},[442,3280,3281],{},"Storage"," trên bảng ",[442,3284,3285],{},"ADMINISTRATION",[435,3287],{"src":3288,"alt":3289,"style":3290},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-administration-storage-menu.webp","Điều hướng đến cài đặt lưu trữ trong bảng điều khiển của TREK","max-width: 539px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[458,3292,617,3293,3296,3249,3297],{},[442,3294,3295],{},"Add Backend"," và điền đầy đủ endpoint, bucket cùng thông tin đăng nhập:",[435,3298],{"src":3299,"alt":3300,"style":3301},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-add-storage-backend-credentials.webp","Cấu hình chương trình lưu trữ Cloudflare R2 tương thích S3","max-width: 445px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[458,3303,3257,3304,3307,3308,3311,3249,3312],{},[442,3305,3306],{},"Apply",", sau đó nhấp vào liên kết nút ",[442,3309,3310],{},"Test",". Bạn sẽ thấy dòng chữ \"Connection OK\":",[435,3313],{"src":3314,"alt":3315,"style":3316},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-test-storage-backend-connection-ok.webp","Kiểm tra kết nối lưu trữ thành công hiển thị Connection OK","max-width: 677px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[458,3318,3319,3320,1276,3249,3323],{},"Chuyển tất cả các danh mục lưu trữ sang Cloudflare R2 và nhấp vào ",[442,3321,3322],{},"Save changes",[435,3324],{"src":3325,"alt":3326,"style":3327},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-switch-storage-categories-r2.webp","Định tuyến tất cả các danh mục lưu trữ tệp sang Cloudflare R2","max-width: 653px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[586,3329,3331],{"id":3330},"_33-đăng-nhập-bằng-passkey","3.3 Đăng nhập bằng Passkey",[429,3333,3334,3335,1276],{},"TREK hỗ trợ đăng nhập bằng passkey, xác thực hai yếu tố (2FA) và đăng nhập một lần OIDC (SSO). Đối với passkey, hãy nhập tên miền của bạn và các origin được phép (allowed origins) trong phần cài đặt, sau đó nhấp vào ",[442,3336,3337],{},"Save",[435,3339],{"src":3340,"alt":3341,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-passkey-allowed-origins-settings.webp","Đăng ký các nguồn gốc được phép để xác thực Passkey an toàn",[429,3343,3344,3345,3348],{},"Nếu không định cấu hình mục ",[442,3346,3347],{},"allowed origins",", việc đăng ký passkey sẽ không thành công.",[586,3350,3352],{"id":3351},"_34-google-maps-api-key","3.4 Google Maps API Key",[429,3354,3355],{},"Khóa Google Maps API giúp bổ sung thêm thông tin phong phú cho việc tìm kiếm địa điểm như xếp hạng, giờ mở cửa và hình ảnh. TREK sẽ tự động chuyển sang sử dụng OpenStreetMap nếu không có khóa, chỉ là không hiển thị xếp hạng và hình ảnh.",[429,3357,3358,3359,3364,3365,3368,3369],{},"Truy cập ",[569,3360,3363],{"href":3361,"rel":3362},"https:\u002F\u002Fmapsplatform.google.com\u002Fmaps-demo-key\u002F",[1654],"liên kết"," này và nhấp vào ",[442,3366,3367],{},"Get demo key"," để yêu cầu cấp khóa:                                                  ",[435,3370],{"src":3371,"alt":3372,"style":3373},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fgoogle-maps-get-demo-api-key.webp","Yêu cầu khóa API của Google Maps Platform","max-width: 176px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3375,3376,3377,3379,3380],{},"Dán khóa vào cài đặt và nhấp vào ",[442,3378,3310],{}," để xác nhận kết nối:\n",[435,3381],{"src":3382,"alt":3383,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-google-maps-key-test-connection.webp","Xác minh khả năng kết nối khóa API Google Maps trong cài đặt",[586,3385,3387],{"id":3386},"_35-tích-hợp-ai","3.5 Tích hợp AI",[429,3389,3390],{},"Mô hình AI được sử dụng để phân tích và chuyển đổi các email xác nhận đặt chỗ cũng như tệp PDF thành các dữ liệu đặt chỗ có cấu trúc.",[429,3392,602,3393,3396,3397,3400],{},[442,3394,3395],{},"Addons"," ở menu bên trái và bật ",[442,3398,3399],{},"AI Parsing",". Chọn \"OpenAI\" (or nhà cung cấp tương thích khác) và điền thông tin chi tiết:",[435,3402],{"src":3403,"alt":3404,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-addons-enable-ai-parsing-openai.webp","Bật tiện ích bổ sung Phân tích cú pháp AI với tích hợp OpenAI",[586,3406,3408],{"id":3407},"_36-truy-cập-qua-mcp","3.6 Truy cập qua MCP",[429,3410,3411,3412,3414,3415,1276],{},"Trong mục ",[442,3413,3395],{},", bật tính năng ",[442,3416,3417],{},"MCP",[435,3419],{"src":3420,"alt":3421,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-addons-enable-mcp.webp","Kích hoạt tiện ích bổ sung máy chủ MCP của Giao thức Ngữ cảnh Mô hình",[586,3423,3425],{"id":3424},"_37-các-plugin","3.7 Các Plugin",[429,3427,3428],{},"Các plugin sau đây được khuyến nghị cài đặt và rất đáng để kích hoạt:",[435,3430],{"src":3431,"alt":3432,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-recommended-addons-plugins-activation.webp","Danh sách các tiện ích bổ sung và plugin được khuyên dùng đang hoạt động",[586,3434,3436],{"id":3435},"_38-tạo-tài-khoản-người-dùng-hàng-ngày","3.8 Tạo tài khoản người dùng hàng ngày",[429,3438,3439],{},"Hãy lập kế hoạch các chuyến đi với tư cách là một người dùng bình thường, thay vì dùng tài khoản quản trị viên. Tạo một người dùng thông thường và đăng nhập bằng tài khoản đó:",[435,3441],{"src":3442,"alt":3443,"style":3444},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-create-regular-user-form.webp","Tạo tài khoản người dùng thông thường trong bảng điều khiển của TREK","max-width: 420px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3446,3447],{},"Sau khi đăng nhập, hãy thêm một passkey hoặc thiết lập xác thực 2FA để tăng cường bảo mật cho tài khoản:",[435,3449],{"src":3450,"alt":3451,"style":3452},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-user-security-passkey-2fa-setup.webp","Cấu hình cài đặt bảo mật của người dùng bằng Passkey và 2FA","max-width: 381px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3454,3257,3455,3458],{},[442,3456,3457],{},"+ Add a passkey",", nhập mật khẩu hiện tại và xác nhận:",[435,3460],{"src":3461,"alt":3462,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-add-passkey-confirm-password.webp","Xác nhận mật khẩu để đăng ký Passkey phần cứng mới",[547,3464,3466],{"id":3465},"_4-kiểm-tra-cài-đặt-nhập-dữ-liệu-du-lịch-trong-quá-khứ","4. Kiểm tra cài đặt: Nhập dữ liệu du lịch trong quá khứ",[429,3468,3469],{},"Cách tuyệt vời nhất để làm quen với TREK là bắt đầu ghi lại lịch sử du lịch trước đây của bạn.",[586,3471,3473],{"id":3472},"_41-tạo-chuyến-đi-mới","4.1 Tạo chuyến đi mới",[429,3475,3257,3476,3479,3480,3483,3484,3487],{},[442,3477,3478],{},"+ New Trip"," và thiết lập ",[442,3481,3482],{},"Start Date"," cũng như ",[442,3485,3486],{},"End Date"," tương ứng với các ngày diễn ra chuyến đi trong quá khứ:",[435,3489],{"src":3490,"alt":3491,"style":3492},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-create-new-trip-details.webp","Tạo một chuyến đi mới với phạm vi ngày tùy chỉnh","max-width: 334px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3494,3495,3496,1276],{},"Thêm ảnh bìa (bằng cách kéo thả hoặc dán từ khay nhớ tạm) rồi nhấp vào ",[442,3497,3498],{},"Create New Trip",[435,3500],{"src":3501,"alt":3502,"style":3503},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-cover-image-upload.webp","Thiết lập ảnh bìa chuyến đi chất lượng cao","max-width: 608px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[586,3505,3507],{"id":3506},"_42-nhập-thông-tin-đặt-chỗ","4.2 Nhập thông tin đặt chỗ",[429,3509,3510],{},"Kéo thả tất cả các tệp thông tin chuyến bay, tàu hỏa và phương tiện di chuyển khác vào:",[435,3512],{"src":3513,"alt":3514,"style":3515},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-import-travel-booking-files.webp","Khu vực kéo và thả để nhập tệp PDF chuyến đi và đặt chỗ","max-width: 570px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[435,3517],{"src":3518,"alt":3519,"style":3520},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-import-booking-pdf-processing-status.webp","Cửa sổ xử lý đặt chỗ đã tải lên hiển thị thông tin trích xuất","max-width: 377px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3522,3523],{},"Khi bật tính năng AI, các tệp PDF xác nhận đặt chỗ sẽ được phân tích tự động và trích xuất thành các bản đặt chỗ có cấu trúc rõ ràng.",[429,3525,3526,3527,3530],{},"Xem lại kết quả đã trích xuất và nhấp vào ",[442,3528,3529],{},"Add"," để lưu thông tin chi tiết đặt chỗ:",[435,3532],{"src":3533,"alt":3534,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-review-parsed-booking-details.webp","Xem xét chi tiết đặt chỗ có cấu trúc được trích xuất bằng AI",[429,3536,3537],{},"Nếu thông tin đặt chỗ chỉ nằm trong email, hãy xuất email đó thành tệp PDF rồi kéo thả vào — quy trình trích xuất tự động tương tự sẽ được áp dụng.",[429,3539,3540],{},"Các ảnh chụp màn hình sau đây hiển thị cách hiển thị của các thông tin đặt chỗ:",[429,3542,3543,3547],{},[435,3544],{"src":3545,"alt":3546,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-bookings-timeline-view.webp","Hiển thị dòng thời gian toàn diện về các lượt đặt chỗ chuyến đi",[435,3548],{"src":3549,"alt":3550,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-booking-confirmation-details.webp","Chế độ xem chi tiết về lượt đặt chỗ phương tiện đã được xác nhận",[429,3552,3553,3554,3557],{},"Trên trang ",[442,3555,3556],{},"Plan",", tất cả các thông tin lưu trú sẽ được hiển thị trực quan trên bản đồ:",[435,3559],{"src":3560,"alt":3561,"style":3562},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-plan-accommodations-map-display.webp","Bản đồ tương tác hiển thị tất cả các nơi lưu trú","max-width: 546px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3564,602,3565,3568],{},[442,3566,3567],{},"Atlas"," trên thanh menu trên cùng để xem danh sách (và bản đồ) hiển thị mọi quốc gia mà bạn đã từng ghé thăm:",[435,3570],{"src":3571,"alt":3572,"style":3573},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-atlas-countries-visited-summary.webp","Tổng quan lịch sử du lịch trong trình theo dõi Atlas cá nhân","max-width: 407px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[586,3575,3577],{"id":3576},"_43-thêm-bạn-đồng-hành","4.3 Thêm bạn đồng hành",[429,3579,617,3580,1276],{},[442,3581,3582],{},"Share",[435,3584],{"src":3585,"alt":3586,"style":3587},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-share-options-button.webp","Mở hộp thoại chia sẻ chuyến đi trong TREK","max-width: 224px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3589,3590],{},"Ở cuối hộp thoại, bạn có thể thêm các khách mời đồng hành (guests):",[435,3592],{"src":3593,"alt":3594,"style":3595},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-add-companions-guests.webp","Thêm bạn đồng hành và khách tùy chỉnh","max-width: 635px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[586,3597,3599],{"id":3598},"_44-ghi-nhận-chi-phí","4.4 Ghi nhận chi phí",[429,3601,3257,3602,3605],{},[442,3603,3604],{},"Add expense"," để thêm các khoản chi phí khác ngoài đặt chỗ, chẳng hạn như bảo hiểm du lịch, phương tiện công cộng địa phương, thẻ SIM:",[435,3607],{"src":3608,"alt":3609,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-add-custom-expense-form.webp","Nhập dữ liệu chi tiêu chi tiết vào biểu mẫu chi phí",[435,3611],{"src":3612,"alt":3613,"style":3614},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-expenses-list-billing-split.webp","Bảng chia hóa đơn và sổ cái theo dõi chi phí","max-width: 526px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[586,3616,3618],{"id":3617},"_45-phân-đoạn-chuyến-đi","4.5 Phân đoạn chuyến đi",[429,3620,3621],{},"Tính năng này yêu cầu plugin Trip Segment phải được kích hoạt trước.",[429,3623,3624],{},"Các chuyến đi dài ngày sẽ được chia nhỏ thành các chặng một cách đẹp mắt, trong đó mỗi chặng hiển thị rõ các thông tin đặt chỗ, địa điểm và chi phí tương ứng:",[435,3626],{"src":3627,"alt":3628,"style":3629},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-segments-overview-display.webp","Chia nhỏ lịch trình phức tạp thành các phân đoạn chuyến đi","max-width: 465px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[435,3631],{"src":3632,"alt":3633,"style":3634},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-segment-itinerary-details.webp","Phân đoạn chuyến đi đang hoạt động hiển thị các địa điểm và lịch trình","max-width: 596px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[435,3636],{"src":3637,"alt":3638,"style":3639},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-segments-interactive-map.webp","Vẽ bản đồ các chặng đi riêng biệt trên dòng thời gian","max-width: 605px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[586,3641,3643],{"id":3642},"_46-tạo-hành-trình-journey-và-kiểm-tra-atlas-của-bạn","4.6 Tạo hành trình (Journey) và kiểm tra atlas của bạn",[429,3645,3646,3647,3650],{},"Gom các chuyến đi thành một ",[442,3648,3649],{},"Journey"," và viết các câu chuyện trải nghiệm để chia sẻ chuyến phiêu lưu với bạn bè:",[435,3652],{"src":3653,"alt":3654,"style":3655},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-create-new-journey-group.webp","Tổng hợp nhiều chuyến đi thành một Hành trình trực quan (Journey)","max-width: 441px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[435,3657],{"src":3658,"alt":3659,"style":3660},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-journey-timeline-story-writing.webp","Soạn thảo các câu chuyện trực quan trong bảng Hành trình","max-width: 443px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[435,3662],{"src":3663,"alt":3664,"style":3665},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-journey-gallery-media-grid.webp","Bộ sưu tập phương tiện và lưới thư viện bên trong một Hành trình","max-width: 440px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[435,3667],{"src":3668,"alt":3669,"style":3670},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-journey-public-share-link.webp","Tạo liên kết chia sẻ công khai cho các Hành trình cộng tác","max-width: 532px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[547,3672,3674],{"id":3673},"_5-thiết-kế-lịch-trình-du-lịch-và-danh-sách-đồ-dùng-cá-nhân","5. Thiết kế lịch trình du lịch và danh sách đồ dùng cá nhân",[429,3676,3257,3677,3679],{},[442,3678,3478],{},", nhập tên chuyến đi và thiết lập ngày tháng:",[435,3681],{"src":3682,"alt":3683,"style":3684},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-planning-new-trip-setup.webp","Hộp thoại nhắc ban đầu để tạo một chuyến đi không ghi ngày","max-width: 432px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3686,3687,3690],{},[442,3688,3689],{},"Nếu bạn chưa chốt ngày đi cụ thể, hãy để trống cả hai mục."," Một trường \"số ngày\" sẽ xuất hiện (cho phép lên đến 365 ngày). Lập kế hoạch trước, xếp lịch sau.",[586,3692,3694],{"id":3693},"_51-thêm-địa-điểm","5.1 Thêm địa điểm",[429,3696,3697],{},"Đây là bước tốn nhiều thời gian nhất của bất kỳ kế hoạch du lịch nào, và TREK cung cấp một số cách để thực hiện điều đó:",[435,3699],{"src":3700,"alt":3701,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-add-places-methods-overview.webp","Các phương pháp đa kênh để thêm địa điểm mới vào lịch trình",[429,3703,3704,3707],{},[442,3705,3706],{},"1. Nhấp chuột phải trên bản đồ"," để tạo một địa điểm tại vị trí chính xác đó — địa chỉ sẽ được xác định tự động bằng tính năng reverse-geocoding:",[435,3709],{"src":3710,"alt":3711,"style":3712},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-right-click-map-location.webp","Nhấp chuột phải vào bản đồ để xác định chính xác vị trí","max-width: 632px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[435,3714],{"src":3715,"alt":3716,"style":3717},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-right-click-reverse-geocode-address.webp","Tự động địa mã hóa ngược các tọa độ bản đồ đã chọn","max-width: 628px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3719,3720,3723],{},[442,3721,3722],{},"2. Nhấp vào + Add Place\u002FActivity"," và tìm kiếm theo tên",[435,3725],{"src":3726,"alt":3727,"style":3728},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-search-place-by-name-input.webp","Tìm kiếm các địa điểm thực tế bằng cách nhập văn bản","max-width: 642px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[435,3730],{"src":3731,"alt":3732,"style":3733},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-select-place-search-results-list.webp","Hiển thị kết quả tìm kiếm địa điểm với thông tin địa chỉ","max-width: 594px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[435,3735],{"src":3736,"alt":3737,"style":3738},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-place-details-rich-info-card.webp","Thẻ thông tin địa điểm toàn diện với các đánh giá và xếp hạng","max-width: 568px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3740,3741,3744,3745,3748,3749,3752],{},[442,3742,3743],{},"3. Dán một đường link Google Maps"," (",[645,3746,3747],{},"maps.app.goo.gl\u002F..."," hoặc ",[645,3750,3751],{},"maps.google.com\u002F...",") vào trường tìm kiếm. TREK sẽ tự động phân tích tên, địa chỉ và tọa độ của địa điểm đó:",[435,3754],{"src":3755,"alt":3756,"style":3316},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-paste-google-maps-share-link.webp","Phân tích cú pháp địa điểm trực tiếp từ liên kết chia sẻ Google Maps được dán",[435,3758],{"src":3759,"alt":3760,"style":3761},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-google-maps-parsed-location.webp","Trích xuất thành công tọa độ từ URL bản đồ","max-width: 543px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3763,3764,3767,3768,3771,3772,2559,3775,3778,3779,3782],{},[442,3765,3766],{},"4. Nhập hàng loạt (Bulk import)"," — cách dễ dàng nhất trong số tất cả. Nếu bạn đã lưu trữ sẵn một danh sách các địa điểm \"muốn đi\" trên Google Maps, hãy xuất danh sách đó dưới dạng ",[645,3769,3770],{},".gpx"," (các định dạng ",[645,3773,3774],{},".kml",[645,3776,3777],{},".kmz"," cũng được hỗ trợ) rồi nhấp vào ",[442,3780,3781],{},"Import file"," ở bảng bên phải để nạp tất cả cùng lúc:",[435,3784],{"src":3785,"alt":3786,"style":3787},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-bulk-import-places-gpx-file.webp","Thực hiện nhập địa điểm hàng loạt bằng tệp GPX hoặc KML","max-width: 389px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3789,3790],{},"Trước tiên hãy thêm tất cả những nơi thú vị mà bạn muốn ghé thăm, bất kể chúng có phù hợp với thời gian hay không. Bạn sẽ phân bổ địa điểm vào các ngày cụ thể sau đó.",[586,3792,3794],{"id":3793},"_52-kế-hoạch-hàng-ngày-và-ghi-chú","5.2 Kế hoạch hàng ngày và ghi chú",[429,3796,3797],{},"Kế hoạch Ngày (Day Plan) sắp xếp các địa điểm theo ngày một cách có thứ tự. Đó là một danh sách có thể thu gọn cho từng ngày, hỗ trợ thao tác kéo thả vô cùng thuận tiện:",[435,3799],{"src":3800,"alt":3801,"style":3802},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-day-plan-drag-drop-ordering.webp","Tùy chỉnh các tuyến đường hàng ngày bằng thao tác kéo và thả","max-width: 496px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3804,3805],{},"Những chi tiết làm nên sự hữu ích của tính năng này:",[455,3807,3808,3818,3828,3838],{},[458,3809,3810,3813,3814],{},[442,3811,3812],{},"Di chuyển giữa các điểm dừng",": biểu tượng xe buýt ở góc trên bên trái của một ngày dùng để thêm thông tin phương tiện công cộng (tàu hỏa, xe buýt hoặc các chặng bay trong ngày):\n",[435,3815],{"src":3816,"alt":3817,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-day-plan-commuting-transport-button.webp","Đăng ký phương tiện di chuyển giữa các phân đoạn trong ngày",[458,3819,3820,3823,3824],{},[442,3821,3822],{},"Ghi chú ngày",": biểu tượng ghi chú ở góc dưới bên trái giúp đính kèm các dòng ghi chú có gắn emoji — \"hôm nay xuất phát sớm\", \"bảo tàng này yêu cầu phải đặt vé trước\":\n",[435,3825],{"src":3826,"alt":3827,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-day-plan-icon-tagged-notes-button.webp","Thêm ghi chú tùy chỉnh có gắn thẻ biểu tượng hiển thị rõ ràng vào các ngày",[458,3829,3830,3833,3834],{},[442,3831,3832],{},"Khung thời gian",": kéo một địa điểm từ bảng bên phải vào một ngày, sau đó thiết lập thời gian cụ thể. Các địa điểm có mốc thời gian cố định sẽ được kết nối lộ trình tự động trên bản đồ:\n",[435,3835],{"src":3836,"alt":3837,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-day-plan-timed-places-routing.webp","Các tuyến đường di chuyển được tính tự động giữa các địa điểm có mốc thời gian",[458,3839,3840,3841,3846,3847,2559,3850,599],{},"Vui lòng tham khảo ",[569,3842,3845],{"href":3843,"rel":3844},"https:\u002F\u002Fgithub.com\u002Fliketrek\u002FTREK\u002Fwiki\u002FDay-Plans-and-Notes",[1654],"trang wiki Day Plans and Notes"," để biết thêm thông tin về ",[442,3848,3849],{},"Tối ưu hóa lộ trình",[442,3851,3852],{},"Thời tiết",[586,3854,3856],{"id":3855},"_53-collections-danh-sách-địa-điểm-có-thể-tái-sử-dụng","5.3 Collections: Danh sách địa điểm có thể tái sử dụng",[429,3858,3859,3860,3863],{},"Tính năng Bộ sưu tập (Collections) cho phép người dùng lưu trữ một danh sách các địa điểm độc lập với bất kỳ chuyến đi cụ thể nào. Nó có thể được chia sẻ với bạn bè và luôn sẵn sàng cho các chuyến đi kế tiếp. Các địa điểm sẽ được ",[442,3861,3862],{},"sao chép"," vào từng chuyến đi, do đó việc chỉnh sửa một địa điểm trong chuyến đi cụ thể sẽ không bao giờ làm thay đổi bộ sưu tập gốc của bạn và ngược lại.",[429,3865,602,3866,3869],{},[442,3867,3868],{},"Collections"," trên thanh menu trên cùng:",[435,3871],{"src":3872,"alt":3873,"style":3874},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-dashboard-view.webp","Truy cập bộ sưu tập tùy chỉnh của người dùng cho các địa điểm đã lưu","max-width: 495px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3876,3257,3877,3880],{},[442,3878,3879],{},"+ New list"," để tạo một danh sách mới:",[435,3882],{"src":3883,"alt":3884,"style":3885},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-create-new-list.webp","Tạo danh sách tùy chỉnh trong bộ sưu tập của người dùng","max-width: 269px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3887,3257,3888,3891],{},[442,3889,3890],{},"+ Add a place"," và điền thông tin chi tiết:",[435,3893],{"src":3894,"alt":3895,"style":3896},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-add-place-manually-form.webp","Nhập biểu mẫu thủ công để đưa địa điểm vào danh sách bộ sưu tập tùy chỉnh","max-width: 271px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3898,3899,3902],{},[442,3900,3901],{},"Lưu ý:"," thanh tìm kiếm bên trong hộp thoại \"Add a place\" dường như chưa hoạt động tốt, vì vậy bạn cần phải nhập các thông tin chi tiết theo cách thủ công.",[429,3904,3905],{},"Nếu các địa điểm có sẵn tọa độ địa lý, chúng sẽ được hiển thị trực tiếp trên bản đồ:",[435,3907],{"src":3908,"alt":3909,"style":3910},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-map-places-display.webp","Trực quan hóa các địa điểm trong bộ sưu tập trên bản đồ tương tác","max-width: 592px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3912,3913,3914,1276],{},"Để sắp xếp các địa điểm bằng nhãn dán (labels), hãy nhấp vào biểu tượng ",[442,3915,3916],{},"hộp kiểm (tick-box)",[435,3918],{"src":3919,"alt":3920,"style":3921},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-select-places-tickbox.webp","Chế độ chọn để gắn nhãn hàng loạt cho các địa điểm đã lưu","max-width: 662px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3923,3924,3925,1276],{},"Chọn các địa điểm muốn nhóm lại, sau đó nhấp vào ",[442,3926,3927],{},"Assign label",[435,3929],{"src":3930,"alt":3931,"style":3761},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-group-assign-label.webp","Gán nhãn mô tả cho các địa điểm bộ sưu tập đã chọn",[429,3933,3257,3934,3937],{},[442,3935,3936],{},"Manage labels"," để tiến hành tạo nhãn trước:",[435,3939],{"src":3940,"alt":3941,"style":3942},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-manage-custom-labels.webp","Tạo và quản lý các nhãn tùy chỉnh","max-width: 411px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,3944,3945,3946,1276],{},"Chọn một nhãn và nhấp vào ",[442,3947,3927],{},[435,3949],{"src":3950,"alt":3951,"style":3573},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-confirm-label-selection.webp","Áp dụng nhãn tùy chỉnh cho các nhóm địa điểm",[586,3953,3955],{"id":3954},"_54-chi-phí-và-ngân-sách","5.4 Chi phí và ngân sách",[429,3957,3958],{},"Chúng ta có thể thêm các khoản chi tiêu khác cho chuyến đi trên trang 'Costs'.",[435,3960],{"src":3961,"alt":3962,"style":3802},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-costs-budget-overall-expenses-list.webp","Bảng chi phí toàn diện và sổ cái quyết toán số dư",[429,3964,3965],{},"Các khoản thanh toán do các bạn đồng hành chi trả có thể được thêm vào và phân chia ngay trên cùng một trang này.",[429,3967,3968,3969,3972],{},"Bảng quyết toán (settlement panel) áp dụng thuật toán so khớp tham lam (greedy-matching algorithm) để tính toán ",[442,3970,3971],{},"số lượng giao dịch chuyển tiền tối thiểu"," cần thực hiện để phân chia công bằng ai nợ ai, và nợ bao nhiêu.",[547,3974,3976],{"id":3975},"_6-khai-thác-model-context-protocol-mcp-để-lập-kế-hoạch-du-lịch-bằng-ai","6. Khai thác Model Context Protocol (MCP) để lập kế hoạch du lịch bằng AI",[429,3978,3979,3980,3983],{},"TREK tích hợp sẵn một ",[442,3981,3982],{},"server MCP (Model Context Protocol)",", cho phép các tác nhân AI đọc và ghi trực tiếp dữ liệu du lịch của bạn — bao gồm hơn 150 công cụ và 30 tài nguyên quản lý các chuyến đi, địa điểm, ngân sách, danh sách đồ dùng, đặt chỗ và cộng tác.",[586,3985,3987],{"id":3986},"_61-cloudflare-zero-trust","6.1 Cloudflare Zero Trust",[429,3989,3990,3991,3994,3995,599],{},"Vì TREK hoạt động phía sau mạng lưới bảo mật ",[569,3992,3993],{"href":363},"Cloudflare Zero Trust",", bạn cần thêm tên miền của mình vào danh sách split tunnels inclusion. Nếu không, bạn sẽ gặp lỗi khi tiến hành xác thực OAuth. Vui lòng tham khảo vấn đề lỗi này trên GitHub: ",[569,3996,3999],{"href":3997,"rel":3998},"https:\u002F\u002Fgithub.com\u002Fliketrek\u002FTREK\u002Fissues\u002F1463",[1654],"github issue",[574,4001],{"description":4002,"image":577,"image-alt":4003,"label":579,"min-read":4004,"title":571,"to":363},"Tìm hiểu cách hiển thị và truy cập an toàn Hermes Agent trên toàn cầu bằng nền tảng Cloudflare WARP và Zero Trust mà không cần mở bất kỳ cổng tường lửa nào.","Hiển thị an toàn Hermes Agent vào mạng riêng bằng Cloudflare Zero Trust và đường hầm WARP","10",[435,4006],{"src":4007,"alt":4008,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fcloudflare-zero-trust-split-tunnels-domain.webp","Thêm tên miền tùy chỉnh vào Cloudflare Warp Split Tunnels",[586,4010,4012],{"id":4011},"_62-claude-desktop","6.2 Claude Desktop",[429,4014,3257,4015,4018,4019],{},[442,4016,4017],{},"+ New Client"," để bắt đầu tạo một AI agent client mới:\n",[435,4020],{"src":4021,"alt":4022,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-register-new-mcp-client.webp","Đăng ký mã thông báo khách tùy chỉnh mới trong cài đặt",[429,4024,4025,4026,4029,4030,1276],{},"Chọn tab ",[442,4027,4028],{},"Claude Desktop"," và nhấp vào ",[442,4031,4032],{},"Register Client",[435,4034],{"src":4035,"alt":4036,"style":4037},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-mcp-claude-desktop-client-credentials.webp","Tạo thông tin xác thực khách của Claude Desktop","max-width: 354px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,4039,4040,4041,4044],{},"Một cặp thông tin bao gồm Client ID và Client Secret sẽ được hiển thị. Hãy sao chép và cất chúng ở nơi an toàn. Sau đó, nhấp vào mục ",[442,4042,4043],{},"Client Configuration"," để hiển thị cấu hình cấu hình MCP:",[435,4046],{"src":4047,"alt":4048,"style":4049},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-mcp-client-configuration-block.webp","Lấy khối cấu hình máy chủ MCP định dạng sẵn","max-width: 508px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,4051,4052,4053,4056],{},"Trong ứng dụng Claude Desktop, nhấp vào ",[442,4054,4055],{},"Edit Config"," để mở tệp cấu hình máy chủ MCP cục bộ:",[435,4058],{"src":4059,"alt":4060,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fclaude-desktop-mcp-config-json.webp","Chỉnh sửa tệp json cấu hình MCP cục bộ của Claude Desktop",[429,4062,4063],{},"Dán cấu hình của TREK vào, thay thế các phần giữ chỗ bằng thông tin xác thực của bạn:",[665,4065,4067],{"className":3077,"code":4066,"language":3079,"meta":424,"style":424},"  \"mcpServers\": {\n    \"trek\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"mcp-remote\",\n        \"https:\u002F\u002Ftrek.pafor.me\u002Fmcp\",\n        \"--static-oauth-client-info\",\n        \"{\\\"client_id\\\": \\\"\u003Cyour_client_id>\\\", \\\"client_secret\\\": \\\"\u003Cyour_client_secret>\\\"}\"\n      ]\n    }\n  },\n",[645,4068,4069,4083,4096,4118,4132,4144,4155,4166,4211,4216,4221],{"__ignoreMap":424},[673,4070,4071,4074,4077,4079,4081],{"class":675,"line":676},[673,4072,4073],{"class":683},"  \"",[673,4075,4076],{"class":687},"mcpServers",[673,4078,691],{"class":683},[673,4080,1077],{"class":2013},[673,4082,1173],{"class":683},[673,4084,4085,4088,4090,4092,4094],{"class":675,"line":741},[673,4086,4087],{"class":683},"    \"",[673,4089,3241],{"class":1279},[673,4091,691],{"class":683},[673,4093,1276],{"class":683},[673,4095,3095],{"class":683},[673,4097,4098,4101,4104,4106,4108,4110,4113,4115],{"class":675,"line":614},[673,4099,4100],{"class":683},"      \"",[673,4102,4103],{"class":679},"command",[673,4105,691],{"class":683},[673,4107,1276],{"class":683},[673,4109,684],{"class":683},[673,4111,4112],{"class":687},"npx",[673,4114,691],{"class":683},[673,4116,4117],{"class":683},",\n",[673,4119,4120,4122,4125,4127,4129],{"class":675,"line":776},[673,4121,4100],{"class":683},[673,4123,4124],{"class":679},"args",[673,4126,691],{"class":683},[673,4128,1276],{"class":683},[673,4130,4131],{"class":683}," [\n",[673,4133,4134,4137,4140,4142],{"class":675,"line":782},[673,4135,4136],{"class":683},"        \"",[673,4138,4139],{"class":687},"mcp-remote",[673,4141,691],{"class":683},[673,4143,4117],{"class":683},[673,4145,4146,4148,4151,4153],{"class":675,"line":827},[673,4147,4136],{"class":683},[673,4149,4150],{"class":687},"https:\u002F\u002Ftrek.pafor.me\u002Fmcp",[673,4152,691],{"class":683},[673,4154,4117],{"class":683},[673,4156,4157,4159,4162,4164],{"class":675,"line":832},[673,4158,4136],{"class":683},[673,4160,4161],{"class":687},"--static-oauth-client-info",[673,4163,691],{"class":683},[673,4165,4117],{"class":683},[673,4167,4168,4170,4172,4175,4178,4180,4182,4184,4187,4189,4191,4193,4196,4198,4200,4202,4205,4207,4209],{"class":675,"line":838},[673,4169,4136],{"class":683},[673,4171,3086],{"class":687},[673,4173,4174],{"class":2013},"\\\"",[673,4176,4177],{"class":687},"client_id",[673,4179,4174],{"class":2013},[673,4181,1077],{"class":687},[673,4183,4174],{"class":2013},[673,4185,4186],{"class":687},"\u003Cyour_client_id>",[673,4188,4174],{"class":2013},[673,4190,1081],{"class":687},[673,4192,4174],{"class":2013},[673,4194,4195],{"class":687},"client_secret",[673,4197,4174],{"class":2013},[673,4199,1077],{"class":687},[673,4201,4174],{"class":2013},[673,4203,4204],{"class":687},"\u003Cyour_client_secret>",[673,4206,4174],{"class":2013},[673,4208,3092],{"class":687},[673,4210,702],{"class":683},[673,4212,4213],{"class":675,"line":850},[673,4214,4215],{"class":683},"      ]\n",[673,4217,4218],{"class":675,"line":855},[673,4219,4220],{"class":683},"    }\n",[673,4222,4223,4226],{"class":675,"line":861},[673,4224,4225],{"class":683},"  }",[673,4227,4117],{"class":2013},[429,4229,4230,4231,1276],{},"Khởi động lại Claude Desktop, khi đó máy chủ TREK sẽ hiển thị trạng thái đã kết nối trong mục ",[442,4232,4233],{},"Local MCP servers",[435,4235],{"src":4236,"alt":4237,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fclaude-desktop-mcp-trek-server-connected.webp","Xác minh trạng thái kết nối TREK đang hoạt động bên trong giao diện Claude",[429,4239,4240],{},"Bây giờ, hãy thử chạy một câu lệnh (prompt):",[435,4242],{"src":4243,"alt":4244,"style":4245},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fclaude-desktop-mcp-natural-language-prompt.webp","Yêu cầu Claude bằng ngôn ngữ tự nhiên để thao tác với dữ liệu du lịch","max-width: 550px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,4247,4248],{},"Hãy thử thêm một khoản chi phí bằng ngôn ngữ tự nhiên:",[665,4250,4253],{"className":4251,"code":4252,"language":1037,"meta":424},[1035],"For the West Europe trip, the Grab from KLIA1 to the hotel cost RM115.90 on 26\u002F4\u002F2025. Please add it as an expense without split to the trip.\n",[645,4254,4252],{"__ignoreMap":424},[435,4256],{"src":4257,"alt":4258,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fclaude-desktop-mcp-add-expense-response.webp","Claude sử dụng các công cụ để tự động ghi lại chi phí",[429,4260,4261,4262,4265],{},"Kiểm tra trang ",[442,4263,4264],{},"Costs",", bạn sẽ thấy chi phí đã được tạo với trạng thái \"No one paid yet\" (Chưa có ai thanh toán) do không có thông tin người chi trả được nhắc đến trong câu lệnh:",[435,4267],{"src":4268,"alt":4269,"style":3215},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-costs-page-mcp-parsed-expense.webp","Xác nhận chi phí AI mới được phân tích cú pháp trong chế độ xem Chi phí",[429,4271,4272],{},"Việc thêm đồ dùng vào danh sách hành lý cũng hoạt động tương tự:",[435,4274],{"src":4275,"alt":4276,"style":4277},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fclaude-desktop-mcp-add-packing-items.webp","Claude thêm các đồ dùng cần chuẩn bị bằng cách nhập ngôn ngữ tự nhiên","max-width: 631px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,4279,4280,4281,4284],{},"Tải lại trang ",[442,4282,4283],{},"Packing List"," và bạn sẽ thấy cả ba vật dụng đã xuất hiện ở đó:",[435,4286],{"src":4287,"alt":4288,"style":4289},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-packing-list-mcp-parsed-items.webp","Xác nhận các đồ dùng mới được phân tích trên trang Danh sách chuẩn bị hành lý","max-width: 312px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[586,4291,4293],{"id":4292},"_63-gemini-cli-đăng-ký-động","6.3 Gemini CLI (Đăng ký động)",[429,4295,4296,4297,4300,4301,1276],{},"Gemini CLI hỗ trợ tính năng ",[442,4298,4299],{},"đăng ký động (dynamic registration)",", nghĩa là bạn không cần tạo trước client. Chỉ cần thêm đoạn sau vào ",[645,4302,4303],{},".gemini\u002Fsettings.json",[665,4305,4307],{"className":3077,"code":4306,"language":3079,"meta":424,"style":424},"    \"trek\": {\n      \"httpUrl\": \"https:\u002F\u002Ftrek.pafor.me\u002Fmcp\",\n      \"oauth\": {\n        \"enabled\": true\n      }\n    }\n",[645,4308,4309,4321,4340,4353,4366,4371],{"__ignoreMap":424},[673,4310,4311,4313,4315,4317,4319],{"class":675,"line":676},[673,4312,4087],{"class":683},[673,4314,3241],{"class":687},[673,4316,691],{"class":683},[673,4318,1077],{"class":2013},[673,4320,1173],{"class":683},[673,4322,4323,4325,4328,4330,4332,4334,4336,4338],{"class":675,"line":741},[673,4324,4100],{"class":683},[673,4326,4327],{"class":1279},"httpUrl",[673,4329,691],{"class":683},[673,4331,1276],{"class":683},[673,4333,684],{"class":683},[673,4335,4150],{"class":687},[673,4337,691],{"class":683},[673,4339,4117],{"class":683},[673,4341,4342,4344,4347,4349,4351],{"class":675,"line":614},[673,4343,4100],{"class":683},[673,4345,4346],{"class":1279},"oauth",[673,4348,691],{"class":683},[673,4350,1276],{"class":683},[673,4352,3095],{"class":683},[673,4354,4355,4357,4360,4362,4364],{"class":675,"line":776},[673,4356,4136],{"class":683},[673,4358,4359],{"class":679},"enabled",[673,4361,691],{"class":683},[673,4363,1276],{"class":683},[673,4365,2234],{"class":683},[673,4367,4368],{"class":675,"line":782},[673,4369,4370],{"class":683},"      }\n",[673,4372,4373],{"class":675,"line":827},[673,4374,4220],{"class":683},[429,4376,4377,4378,4381,4382,4385,4386],{},"Chạy lệnh ",[645,4379,4380],{},"gemini"," trong terminal và nhấp vào ",[442,4383,4384],{},"Approve"," khi hộp thoại yêu cầu xác thực xuất hiện:\n",[435,4387],{"src":4388,"alt":4389,"style":4390},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fmcp-client-oauth-authorization-prompt.webp","Phê duyệt quyền truy cập OAuth cho máy chủ TREK MCP","max-width: 488px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,4392,4393],{},"Sau đó bắt đầu bằng một câu lệnh đơn giản:",[435,4395],{"src":4396,"alt":4397,"style":4398},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fgemini-cli-mcp-prompt-itinerary.webp","Yêu cầu Gemini CLI tìm lịch trình du lịch","max-width: 415px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[435,4400],{"src":4401,"alt":4402,"style":3665},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fgemini-cli-mcp-display-itinerary.webp","Gemini CLI hiển thị thành công thông tin chuyến đi có cấu trúc",[586,4404,4406],{"id":4405},"_64-kimi-cli-đăng-ký-động","6.4 Kimi CLI (Đăng ký động)",[429,4408,4409,4410,4413,4414,1276],{},"Cách tiếp cận tương tự — thêm đoạn cấu hình vào file ",[645,4411,4412],{},"mcp.json"," nằm trong thư mục ",[645,4415,4416],{},"\u002FUsers\u002F\u003Cuser>\u002F.kimi\u002F",[665,4418,4420],{"className":3077,"code":4419,"language":3079,"meta":424,"style":424},"    \"trek\": {\n      \"type\": \"http\",\n      \"url\": \"https:\u002F\u002Ftrek.pafor.me\u002Fmcp\",\n      \"auth\": \"oauth\"\n    }\n",[645,4421,4422,4434,4454,4473,4490],{"__ignoreMap":424},[673,4423,4424,4426,4428,4430,4432],{"class":675,"line":676},[673,4425,4087],{"class":683},[673,4427,3241],{"class":687},[673,4429,691],{"class":683},[673,4431,1077],{"class":2013},[673,4433,1173],{"class":683},[673,4435,4436,4438,4441,4443,4445,4447,4450,4452],{"class":675,"line":741},[673,4437,4100],{"class":683},[673,4439,4440],{"class":1279},"type",[673,4442,691],{"class":683},[673,4444,1276],{"class":683},[673,4446,684],{"class":683},[673,4448,4449],{"class":687},"http",[673,4451,691],{"class":683},[673,4453,4117],{"class":683},[673,4455,4456,4458,4461,4463,4465,4467,4469,4471],{"class":675,"line":614},[673,4457,4100],{"class":683},[673,4459,4460],{"class":1279},"url",[673,4462,691],{"class":683},[673,4464,1276],{"class":683},[673,4466,684],{"class":683},[673,4468,4150],{"class":687},[673,4470,691],{"class":683},[673,4472,4117],{"class":683},[673,4474,4475,4477,4480,4482,4484,4486,4488],{"class":675,"line":776},[673,4476,4100],{"class":683},[673,4478,4479],{"class":1279},"auth",[673,4481,691],{"class":683},[673,4483,1276],{"class":683},[673,4485,684],{"class":683},[673,4487,4346],{"class":687},[673,4489,702],{"class":683},[673,4491,4492],{"class":675,"line":782},[673,4493,4220],{"class":683},[429,4495,4377,4496,4381,4499,1261,4501],{},[645,4497,4498],{},"kimi mcp auth trek",[442,4500,4384],{},[435,4502],{"src":4388,"alt":4389,"style":4503},"max-width: 453px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,4505,4506],{},"Sau khi hoàn tất xác thực, danh sách các công cụ có sẵn sẽ được liệt kê:",[435,4508],{"src":4509,"alt":4510,"style":3046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fkimi-cli-mcp-authorized-tools-list.webp","Kimi CLI hiển thị các công cụ có sẵn sau khi ủy quyền thành công",[547,4512,4514],{"id":4513},"_7-trải-nghiệm-trên-thiết-bị-di-động","7. Trải nghiệm trên thiết bị di động",[429,4516,4517],{},"TREK là một Ứng dụng Web Lũy tiến (PWA) trên các thiết bị di động. Một service worker sẽ lưu bộ nhớ đệm (cache) cho các phần bản đồ và dữ liệu API, giúp lịch trình của bạn luôn có thể đọc được ngay cả khi ngoại tuyến (offline). Tuy nhiên, tính năng thông báo đẩy có thể gặp một chút độ trễ so với ứng dụng gốc (native app).\"",[547,4519,2606],{"id":2605},[429,4521,4522],{},"Kết nối các tác nhân AI thông qua giao thức MCP giúp giảm thiểu phần lớn công việc tẻ nhạt khi nhập dữ liệu đặt chỗ chuyến bay và chỗ ở. Ngoài ra, các tác nhân cũng có thể đề xuất các địa điểm tham quan thú vị dựa trên ngày du lịch và mùa cụ thể trong năm của bạn. Chỉ với một cuộc hội thoại duy nhất với một AI agent, bạn có thể xử lý toàn bộ quy trình, từ tìm kiếm nghiên cứu, xây dựng lịch trình cho đến theo dõi ngân sách và sắp xếp hành lý.",[429,4524,4525],{},"Tuy nhiên, ứng dụng vẫn tồn tại một số lỗi kỹ thuật nhỏ. Ví dụ: khi nhập dữ liệu đặt chỗ từ tệp PDF, đơn vị tiền tệ sẽ tự động đặt mặc định theo đồng tiền gốc của chuyến đi thay vì đơn vị tiền tệ thực tế đã thanh toán. Ngoài ra, khi tạo một danh sách mới trong Collections, bất kỳ ảnh bìa nào được thêm vào trong quá trình tạo đều sẽ biến mất sau khi lưu, mặc dù bạn hoàn toàn có thể tự đính kèm lại một cách thủ công khi chỉnh sửa.",[429,4527,4528,4529,4534],{},"Bên cạnh đó, việc tự lưu trữ cũng tạo ra một rào cản kỹ thuật nhỏ khi bạn cần phải vận hành nó trên máy chủ của riêng mình. TREK được thiết kế chủ yếu dành cho những người đi du lịch thường xuyên và có kỳ vọng rất cao về cách họ quản lý và tổ chức dữ liệu du lịch của mình. Chúng tôi khuyên bạn nên thử nghiệm bản demo chính thức tại ",[569,4530,4533],{"href":4531,"rel":4532},"https:\u002F\u002Fdemo.liketrek.com\u002F",[1654],"demo.liketrek.com"," trước khi quyết định tự host.",[547,4536,4537],{"id":2612},"Tài liệu tham khảo:",[455,4539,4540,4547,4554],{},[458,4541,4542],{},[569,4543,4546],{"href":4544,"rel":4545},"https:\u002F\u002Fgithub.com\u002Fliketrek\u002FTREK\u002Fwiki\u002FQuick-Start",[1654],"TREK Quick Start",[458,4548,4549],{},[569,4550,4553],{"href":4551,"rel":4552},"https:\u002F\u002Fgithub.com\u002Fliketrek\u002FTREK\u002Fwiki\u002FTroubleshooting",[1654],"TREK Troubleshooting",[458,4555,4556],{},[569,4557,4560],{"href":4558,"rel":4559},"https:\u002F\u002Fgithub.com\u002Fliketrek\u002FTREK\u002Fwiki\u002FMCP-Scopes",[1654],"TREK MCP Scopes",[2645,4562,4563],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":424,"searchDepth":741,"depth":614,"links":4565},[4566,4571,4572,4582,4590,4596,4602,4603,4604],{"id":2740,"depth":614,"text":2741,"children":4567},[4568,4569,4570],{"id":2744,"depth":776,"text":2745},{"id":2890,"depth":776,"text":2891},{"id":2922,"depth":776,"text":2923},{"id":3067,"depth":614,"text":3068},{"id":3117,"depth":614,"text":3118,"children":4573},[4574,4575,4576,4577,4578,4579,4580,4581],{"id":3218,"depth":776,"text":3219},{"id":3229,"depth":776,"text":3230},{"id":3330,"depth":776,"text":3331},{"id":3351,"depth":776,"text":3352},{"id":3386,"depth":776,"text":3387},{"id":3407,"depth":776,"text":3408},{"id":3424,"depth":776,"text":3425},{"id":3435,"depth":776,"text":3436},{"id":3465,"depth":614,"text":3466,"children":4583},[4584,4585,4586,4587,4588,4589],{"id":3472,"depth":776,"text":3473},{"id":3506,"depth":776,"text":3507},{"id":3576,"depth":776,"text":3577},{"id":3598,"depth":776,"text":3599},{"id":3617,"depth":776,"text":3618},{"id":3642,"depth":776,"text":3643},{"id":3673,"depth":614,"text":3674,"children":4591},[4592,4593,4594,4595],{"id":3693,"depth":776,"text":3694},{"id":3793,"depth":776,"text":3794},{"id":3855,"depth":776,"text":3856},{"id":3954,"depth":776,"text":3955},{"id":3975,"depth":614,"text":3976,"children":4597},[4598,4599,4600,4601],{"id":3986,"depth":776,"text":3987},{"id":4011,"depth":776,"text":4012},{"id":4292,"depth":776,"text":4293},{"id":4405,"depth":776,"text":4406},{"id":4513,"depth":614,"text":4514},{"id":2605,"depth":614,"text":2606},{"id":2612,"depth":614,"text":4537},[4606,2680],"travel","2026-09-01","Tìm hiểu cách triển khai TREK với Docker, bảo mật qua Cloudflare R2 và Caddy, đồng thời sử dụng các tác nhân AI qua MCP để lập kế hoạch du lịch liền mạch.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002FVI-Self-hosted-travel-planner-TREK.webp","Ảnh minh họa 3D tối giản cao cấp về bảng điều khiển du lịch tự lưu trữ TREK trên nền giấy da ấm áp.",{"schemaOrg":4612,"robots":2709,"sitemap":4617},[4613,4614],{"@type":2691,"headline":2726,"description":4608},{"@type":4615,"headline":4616,"description":4608},"Article","Cách tự host TREK: Trình lên kế hoạch du lịch AI tốt nhất",{"lastmod":4607},{"title":4616,"description":4608,"ogTitle":2726,"ogDescription":4608,"twitterTitle":2726,"twitterDescription":4608},"vi\u002Farticle\u002Fself-hosted-travel-planner-trek",[2717,4621,2718,2719,3417],"TREK","OaVc2953r8KK1STCJIu9QaiDbBUH-OlsozrztOE9Zwg",{"id":4624,"title":4625,"author":424,"body":4626,"category":6004,"date":6006,"description":6007,"extension":2683,"image":6008,"imageAlt":6009,"isPublished":772,"meta":6010,"minRead":919,"navigation":772,"path":307,"seo":6016,"stem":6018,"tags":6019,"updatedAt":2720,"__hash__":6024},"article\u002Fvi\u002Farticle\u002Fsync-obsidian-across-devices.md","Cách đồng bộ vault Obsidian qua các thiết bị an toàn",{"type":426,"value":4627,"toc":5982},[4628,4631,4636,4645,4654,4670,4675,4681,4685,4690,4704,4720,4723,4727,4731,4737,4742,4746,4751,4802,4808,4838,4842,4849,4856,4862,4914,4917,4932,4937,4949,4953,4957,4963,4968,4978,4999,5004,5018,5023,5028,5033,5047,5050,5054,5057,5062,5066,5071,5084,5088,5102,5112,5116,5121,5124,5134,5167,5171,5178,5306,5339,5344,5364,5375,5380,5384,5394,5466,5470,5475,5511,5640,5647,5653,5659,5665,5668,5674,5680,5694,5705,5712,5718,5725,5856,5862,5867,5870,5875,5878,5882,5887,5892,5898,5909,5919,5923,5934,5940,5946,5952,5956,5979],[429,4629,4630],{},"Obsidian là một ứng dụng quản lý ghi chú\u002Ftri thức theo triết lý local-first (ưu tiên lưu trữ cục bộ). Mỗi ghi chú thực chất là một file markdown nằm trên thiết bị và hoàn toàn thuộc quyền kiểm soát của bạn. Tuy nhiên, chúng ta thường mong muốn đồng bộ cùng một vault (kho ghi chú) trên cả laptop, điện thoại và các thiết bị khác, hoặc có thể truy cập từ xa thông qua trình duyệt web khi cần thiết.",[435,4632],{"src":4633,"alt":4634,"style":4635},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-multi-device-sync-illustration.webp","Hình minh họa kho ghi chú Obsidian được đồng bộ trên nhiều thiết bị","max-width: 667px; width: 100%; height: auto;",[429,4637,4638,4639,4644],{},"Hiện có nhiều giải pháp đồng bộ hóa cho Obsidian, nhưng chúng đều phải đánh đổi giữa tính năng xử lý xung đột, bảo mật mã hóa và chủ quyền dữ liệu cá nhân. ",[569,4640,4643],{"href":4641,"rel":4642},"https:\u002F\u002Fgithub.com\u002Fhjinco\u002Fsynch",[1654],"Synch"," là một ứng dụng mã nguồn mở giúp đồng bộ hóa các vault Obsidian với cơ chế mã hóa đầu cuối (E2E) và tự động giải quyết xung đột trên máy chủ tự host.",[429,4646,4647,4648,4653],{},"Mặc dù phương pháp local-first của Obsidian hoạt động hoàn hảo trong hầu hết thời gian, đôi khi chúng ta vẫn cần truy cập ghi chú từ xa qua trình duyệt web. ",[569,4649,4652],{"href":4650,"rel":4651},"https:\u002F\u002Fgithub.com\u002FNystik-gh\u002Fignis",[1654],"Ignis"," là giải pháp mã nguồn mở cho phép chạy Obsidian trực tiếp trên trình duyệt web với trải nghiệm gần như ứng dụng gốc, giúp bạn dễ dàng đọc và chỉnh sửa ghi chú từ bất kỳ đâu.",[429,4655,4656,4657,2559,4659,4661,4662,4664,4665,4669],{},"Trong hướng dẫn này, chúng ta sẽ thiết lập ",[442,4658,4643],{},[442,4660,4652],{}," trên một ",[442,4663,1676],{},", đồng thời bảo mật chúng bên trong mạng riêng ",[442,4666,4667],{},[569,4668,3993],{"href":363}," thay vì mở trực tiếp ra internet công cộng.",[435,4671],{"src":4672,"alt":4673,"style":4674},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-sync-cloudflare-zero-trust-architecture.webp","Sơ đồ kiến trúc đồng bộ Obsidian sử dụng Cloudflare Zero Trust","max-width: 671px; width: 100%; height: auto;",[574,4676],{"description":4677,"image":4678,"image-alt":4679,"label":579,"min-read":580,"title":4680,"to":363},"Tìm hiểu cách expose và truy cập an toàn vào Hermes Agent của bạn trên toàn cầu bằng Cloudflare WARP và Zero Trust mà không cần mở cổng firewall inbound.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002FEN-Exposing-Hermes-Agent-to-Private-Network-Using-Cloudflare-WARP.webp","Thiết lập mạng riêng tư an toàn sử dụng Cloudflare Zero Trust và đường truyền WARP tunnel","Cách expose Hermes Agent riêng tư bằng Cloudflare WARP",[447,4682,4684],{"id":4683},"đồng-bộ-hóa-vault-obsidian-bảo-mật-với-synch","Đồng bộ hóa Vault Obsidian bảo mật với Synch",[429,4686,4687,4689],{},[442,4688,4643],{}," cung cấp các tính năng nổi bật sau:",[455,4691,4692,4695,4698,4701],{},[458,4693,4694],{},"Đồng bộ hóa vault ngay khi phát hiện thay đổi",[458,4696,4697],{},"Mã hóa dữ liệu vault đầu cuối trước khi upload",[458,4699,4700],{},"Khôi phục từ lịch sử phiên bản",[458,4702,4703],{},"Tự động xử lý và giải quyết xung đột file",[429,4705,4706,4708,4709,4712,4713,4716,4717,4719],{},[442,4707,4643],{}," tạo ra một ",[442,4710,4711],{},"vault key"," (khóa giải mã) 32-byte ngẫu nhiên trên thiết bị của bạn, dùng để mã hóa toàn bộ dữ liệu ghi chú. Khi tạo vault từ xa, bạn sẽ chọn một ",[442,4714,4715],{},"vault password"," (mật khẩu vault); mật khẩu này dùng để bảo vệ ",[442,4718,4711],{}," để khóa có thể được lưu trữ an toàn trên server và giải mã trên các thiết bị khác của bạn.",[429,4721,4722],{},"Việc giải quyết xung đột ghi chú được xử lý trực tiếp trên thiết bị khách (client) thay vì trên server. Nếu hai thiết bị cùng chỉnh sửa một ghi chú đồng thời, server sẽ giữ phiên bản nào gửi đến trước và báo cho thiết bị còn lại rằng file của họ đã lỗi thời. Thiết bị đó sẽ tự động gộp phiên bản mới từ server vào các thay đổi cục bộ của mình rồi mới upload bản ghi chú cuối cùng lên.",[547,4724,4726],{"id":4725},"thiết-lập-synch-trên-vps","Thiết lập Synch trên VPS",[586,4728,4730],{"id":4729},"tạo-bản-ghi-tên-miền-dns","Tạo Bản ghi Tên miền (DNS)",[429,4732,4733,4734,4736],{},"Tạo một bản ghi A trên Cloudflare và đặt trạng thái proxy là ",[442,4735,714],{}," (bỏ qua CDN của Cloudflare).",[435,4738],{"src":4739,"alt":4740,"style":4741},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fcloudflare-dns-a-record-synch-server.webp","Cấu hình bản ghi DNS A cho máy chủ Synch trong Cloudflare","max-width: 538px; width: 100%; height: auto;",[586,4743,4745],{"id":4744},"cài-đặt-synch-docker-trên-ubuntu","Cài đặt Synch Docker trên Ubuntu",[4747,4748,4750],"h5",{"id":4749},"clone-repository","Clone Repository",[665,4752,4754],{"className":667,"code":4753,"language":669,"meta":424,"style":424},"git clone https:\u002F\u002Fgithub.com\u002Fhjinco\u002Fsynch.git       \n        \n# Navigate to the API folder\ncd synch\u002Fapps\u002Fapi\n        \n# Copy the example environment file:\ncp .env.example .env\n",[645,4755,4756,4768,4773,4778,4785,4789,4794],{"__ignoreMap":424},[673,4757,4758,4760,4762,4765],{"class":675,"line":676},[673,4759,981],{"class":679},[673,4761,984],{"class":687},[673,4763,4764],{"class":687}," https:\u002F\u002Fgithub.com\u002Fhjinco\u002Fsynch.git",[673,4766,4767],{"class":2013},"       \n",[673,4769,4770],{"class":675,"line":741},[673,4771,4772],{"class":2013},"        \n",[673,4774,4775],{"class":675,"line":614},[673,4776,4777],{"class":737},"# Navigate to the API folder\n",[673,4779,4780,4782],{"class":675,"line":776},[673,4781,996],{"class":785},[673,4783,4784],{"class":687}," synch\u002Fapps\u002Fapi\n",[673,4786,4787],{"class":675,"line":782},[673,4788,4772],{"class":2013},[673,4790,4791],{"class":675,"line":827},[673,4792,4793],{"class":737},"# Copy the example environment file:\n",[673,4795,4796,4798,4800],{"class":675,"line":832},[673,4797,1004],{"class":679},[673,4799,1007],{"class":687},[673,4801,1010],{"class":687},[4747,4803,4805,4806],{"id":4804},"chỉnh-sửa-các-giá-trị-trong-env","Chỉnh sửa các giá trị trong ",[645,4807,1023],{},[455,4809,4810,4816,4832],{},[458,4811,4812,4815],{},[645,4813,4814],{},"PUBLIC_URL=synch.pafor.me",": Điền tên miền công cộng của server Synch (tên miền bạn vừa cấu hình ở bước trên).",[458,4817,4818,2559,4821,4824,4825,4828,4829,4831],{},[645,4819,4820],{},"BETTER_AUTH_SECRET",[645,4822,4823],{},"SYNC_TOKEN_SECRET",": Tạo các khóa bí mật bảo mật bằng cách sử dụng ",[569,4826,4827],{"href":1064},"công cụ tạo key online"," hoặc chạy lệnh ",[645,4830,1069],{}," hai lần trong terminal của bạn.",[458,4833,4834,4837],{},[645,4835,4836],{},"AUTH_ALLOWED_EMAILS",": Danh sách các email được phép đăng ký và tạo tài khoản (ngăn cách bằng dấu phẩy).",[4747,4839,4841],{"id":4840},"thêm-tên-miền-vào-caddyfile","Thêm Tên miền vào Caddyfile",[429,4843,4844,4845,599],{},"Thông tin chi tiết về cách tích hợp module Cloudflare DNS vào Caddy và chạy bằng Docker container được trình bày trong ",[569,4846,4848],{"href":4847},"\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues#_4-enable-https-with-caddy","bài viết tự host Buzz của chúng tôi",[574,4850],{"description":4851,"image":4852,"image-alt":4853,"label":4854,"min-read":4855,"title":423,"to":4847},"Tìm hiểu cách định cấu hình Caddy để tự động cấp chứng chỉ SSL\u002FTLS bằng cách sử dụng các thử thách DNS của Cloudflare trong các vùng chứa Docker.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002FEN-Self-Hosting-Buzz-As-The-Workspace-Where-AI-Agents-Become-Colleagues.webp","Định cấu hình Caddy bằng token API Cloudflare DNS để tự động tạo chứng chỉ SSL\u002FTLS trong không gian làm việc tự host","Hướng dẫn tự host","12",[429,4857,1109,4858,4861],{},[645,4859,4860],{},"SYNCH_DOMAIN"," vào file Caddyfile và trỏ về cổng 8787 của container Synch:",[665,4863,4865],{"className":3077,"code":4864,"language":3079,"meta":424,"style":424},"{\n  acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}\n}\n\n{$SYNCH_DOMAIN} {\n  encode zstd gzip\n  reverse_proxy host.docker.internal:8787\n}\n",[645,4866,4867,4871,4878,4882,4886,4897,4901,4910],{"__ignoreMap":424},[673,4868,4869],{"class":675,"line":676},[673,4870,1173],{"class":683},[673,4872,4873,4876],{"class":675,"line":741},[673,4874,4875],{"class":2013},"  acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN",[673,4877,1187],{"class":683},[673,4879,4880],{"class":675,"line":614},[673,4881,1187],{"class":2013},[673,4883,4884],{"class":675,"line":776},[673,4885,773],{"emptyLinePlaceholder":772},[673,4887,4888,4890,4893,4895],{"class":675,"line":782},[673,4889,3086],{"class":683},[673,4891,4892],{"class":2013},"$SYNCH_DOMAIN",[673,4894,3092],{"class":683},[673,4896,3095],{"class":683},[673,4898,4899],{"class":675,"line":827},[673,4900,3100],{"class":2013},[673,4902,4903,4905,4907],{"class":675,"line":832},[673,4904,3105],{"class":2013},[673,4906,1276],{"class":683},[673,4908,4909],{"class":1311},"8787\n",[673,4911,4912],{"class":675,"line":838},[673,4913,1187],{"class":683},[429,4915,4916],{},"Khởi chạy container:",[665,4918,4920],{"className":667,"code":4919,"language":669,"meta":424,"style":424},"docker compose up -d\n",[645,4921,4922],{"__ignoreMap":424},[673,4923,4924,4926,4928,4930],{"class":675,"line":676},[673,4925,922],{"class":679},[673,4927,964],{"class":687},[673,4929,1561],{"class":687},[673,4931,1564],{"class":687},[429,4933,4377,4934,4936],{},[645,4935,680],{}," sau để kiểm tra xem hệ thống đã hoạt động chưa:",[665,4938,4940],{"className":667,"code":4939,"language":669,"meta":424,"style":424},"curl https:\u002F\u002Fsynch.pafor.me\u002Fhealth\n",[645,4941,4942],{"__ignoreMap":424},[673,4943,4944,4946],{"class":675,"line":676},[673,4945,680],{"class":679},[673,4947,4948],{"class":687}," https:\u002F\u002Fsynch.pafor.me\u002Fhealth\n",[547,4950,4952],{"id":4951},"kết-nối-obsidian-với-server-synch","Kết nối Obsidian với Server Synch",[586,4954,4956],{"id":4955},"cài-đặt-plugin-synch-trên-obsidian","Cài đặt Plugin Synch trên Obsidian",[429,4958,4959,4960,1276],{},"Vào Cài đặt (Settings) -> Community plugins và nhấn nút ",[442,4961,4962],{},"'Browse'",[435,4964],{"src":4965,"alt":4966,"style":4967},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-community-plugins-browse.webp","Duyệt các plugin cộng đồng trong cài đặt Obsidian","max-width: 523px; width: 100%; height: auto;",[429,4969,4970,4971,1261,4974],{},"Tìm kiếm và cài đặt plugin ",[442,4972,4973],{},"'Synchrun'",[435,4975],{"src":4976,"alt":4977,"style":4741},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-install-synchrun-plugin.webp","Cài đặt plugin Synchrun trong Obsidian",[429,4979,4980,4981,4983,4984,4987,4988,4991,4992,4995,4996,599],{},"Sau khi cài đặt xong ",[442,4982,4973],{},", vào phần cài đặt của plugin này, kích hoạt tùy chọn ",[442,4985,4986],{},"'Use a self-hosted server'",". Điền địa chỉ ",[645,4989,4990],{},"https:\u002F\u002Fsynch.pafor.me"," vào trường ",[442,4993,4994],{},"'Server URL'"," và nhấn ",[442,4997,4998],{},"'Save'",[435,5000],{"src":5001,"alt":5002,"style":5003},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-synchrun-plugin-settings-self-hosted.webp","Cấu hình URL máy chủ tự host trong cài đặt plugin Synchrun","max-width: 525px; width: 100%; height: auto;",[429,5005,5006,5007,5010,5011,5014,5015,5017],{},"Nhấn nút ",[442,5008,5009],{},"'Sign in on this device'"," bên dưới mục ",[442,5012,5013],{},"'Account'",". Tiến hành đăng ký tài khoản (hãy sử dụng đúng email bạn đã khai báo trong danh sách ",[645,5016,4836],{},"), bạn sẽ được chuyển đến trang ủy quyền sau:",[435,5019],{"src":5020,"alt":5021,"style":5022},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynchrun-account-authorization-page.webp","Trang ủy quyền tài khoản cho Synchrun","max-width: 494px; width: 100%; height: auto;",[429,5024,5006,5025,1276],{},[442,5026,5027],{},"'Allow Obsidian sign-in'",[435,5029],{"src":5030,"alt":5031,"style":5032},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynchrun-allow-obsidian-signin.webp","Cho phép đăng nhập Obsidian cho Synch","max-width: 498px; width: 100%; height: auto;",[429,5034,5006,5035,5038,5039,1261,5042],{},[442,5036,5037],{},"'Return to Obsidian'"," rồi click chọn ",[442,5040,5041],{},"'Create vault'",[435,5043],{"src":5044,"alt":5045,"style":5046},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-synchrun-create-remote-vault.webp","Tạo một kho ghi chú từ xa mới trong Synchrun","max-width: 496px; width: 100%; height: auto;",[429,5048,5049],{},"Đặt tên cho vault và mật khẩu để tạo vault mới.",[435,5051],{"src":5052,"alt":5053,"style":1599},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-synchrun-vault-password-setup.webp","Thiết lập mật khẩu an toàn cho kho ghi chú từ xa Obsidian",[429,5055,5056],{},"Quá trình đồng bộ hóa sẽ bắt đầu ngay lập tức và có thể mất một thời gian tùy theo dung lượng vault của bạn. Khi đồng bộ hoàn tất, dung lượng bộ nhớ đã sử dụng sẽ được hiển thị.",[435,5058],{"src":5059,"alt":5060,"style":5061},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-synchrun-sync-completed-storage.webp","Đồng bộ Synchrun hoàn tất hiển thị tổng dung lượng đã sử dụng","max-width: 508px; width: 100%; height: auto;",[447,5063,5065],{"id":5064},"truy-cập-obsidian-qua-web-bằng-ignis","Truy cập Obsidian qua Web bằng Ignis",[429,5067,5068,5070],{},[442,5069,4652],{}," thay thế các Electron API của Obsidian bằng Web API, cho phép mã nguồn JavaScript của Obsidian chạy trực tiếp trên trình duyệt web tiêu chuẩn. Tất cả các file markdown và tài liệu đính kèm đều được lưu trực tiếp trên hệ thống file của máy chủ host.",[429,5072,5073,5074,2559,5079,2387],{},"Tuy nhiên, do hạn chế của môi trường sandbox trình duyệt, một số tính năng hoặc plugin yêu cầu truy cập API của Node.js hoặc Electron sẽ không thể hoạt động. Vui lòng tham khảo các hướng dẫn về ",[569,5075,5078],{"href":5076,"rel":5077},"https:\u002F\u002Fignis.thiefling.com\u002Fdocs\u002Fusing\u002Flimitations\u002F",[1654],"Hạn chế của Ignis",[569,5080,5083],{"href":5081,"rel":5082},"https:\u002F\u002Fignis.thiefling.com\u002Fdocs\u002Fusing\u002Fplugin-compatibility\u002F",[1654],"Khả năng tương thích plugin",[547,5085,5087],{"id":5086},"cài-đặt-ignis","Cài đặt Ignis",[429,5089,5090,5091,5093,5094,5097,5098,5101],{},"Chúng ta sẽ cài đặt ",[442,5092,4652],{}," trên VPS bằng Docker và mount thư mục lưu trữ vào ",[645,5095,5096],{},".\u002Fvaults",". Thư mục này sau đó sẽ được đồng bộ hóa tự động bằng ",[442,5099,5100],{},"Synch CLI"," với vault từ xa mà chúng ta đã thiết lập ở phần trước.",[429,5103,5104,5105,5107,5108,599],{},"Vì ",[442,5106,4652],{}," không có sẵn hệ thống xác thực người dùng, chúng ta sẽ giấu nó an toàn đằng sau mạng riêng ảo ",[442,5109,5110],{},[569,5111,3993],{"href":363},[586,5113,5115],{"id":5114},"tạo-bản-ghi-dns","Tạo Bản ghi DNS",[435,5117],{"src":5118,"alt":5119,"style":5120},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fcloudflare-dns-a-record-ignis.webp","Cấu hình bản ghi DNS A cho ứng dụng web Ignis trong Cloudflare","max-width: 552px; width: 100%; height: auto;",[586,5122,4841],{"id":5123},"thêm-tên-miền-vào-caddyfile-1",[429,5125,5126,5127,5130,5131,1276],{},"Thêm tên miền ",[645,5128,5129],{},"obsidian.pafor.me"," vào Caddyfile tương tự như cách làm với ",[645,5132,5133],{},"synch.pafor.me",[665,5135,5137],{"className":3077,"code":5136,"language":3079,"meta":424,"style":424},"{$OBSIDIAN_DOMAIN} {\n  encode zstd gzip\n  reverse_proxy host.docker.internal:9898\n}\n",[645,5138,5139,5150,5154,5163],{"__ignoreMap":424},[673,5140,5141,5143,5146,5148],{"class":675,"line":676},[673,5142,3086],{"class":683},[673,5144,5145],{"class":2013},"$OBSIDIAN_DOMAIN",[673,5147,3092],{"class":683},[673,5149,3095],{"class":683},[673,5151,5152],{"class":675,"line":741},[673,5153,3100],{"class":2013},[673,5155,5156,5158,5160],{"class":675,"line":614},[673,5157,3105],{"class":2013},[673,5159,1276],{"class":683},[673,5161,5162],{"class":1311},"9898\n",[673,5164,5165],{"class":675,"line":776},[673,5166,1187],{"class":683},[586,5168,5170],{"id":5169},"khởi-chạy-ignis-bằng-docker","Khởi chạy Ignis bằng Docker",[429,5172,5173,5174,5177],{},"Lưu file cấu hình Docker Compose sau thành ",[645,5175,5176],{},"ignis-docker-compose.yml"," trên VPS:",[665,5179,5181],{"className":1164,"code":5180,"language":1166,"meta":424,"style":424},"services:\n  ignis:\n    image: nobbe\u002Fignis:latest\n    ports:\n      - \"9898:8080\"\n    environment:\n      # match these to your host user (run: id)\n      - PUID=1000\n      - PGID=1000\n      - WS_ORIGINS=https:\u002F\u002Fobsidian.pafor.me\n    volumes:\n      - .\u002Fvaults:\u002Fvaults\n      - .\u002Fdata:\u002Fapp\u002Fdata\n      - obsidian-app:\u002Fapp\u002Fobsidian-app\n    restart: unless-stopped\n\nvolumes:\n  obsidian-app:\n",[645,5182,5183,5189,5196,5205,5211,5222,5228,5233,5240,5247,5254,5260,5267,5274,5281,5289,5293,5299],{"__ignoreMap":424},[673,5184,5185,5187],{"class":675,"line":676},[673,5186,1258],{"class":1257},[673,5188,1261],{"class":683},[673,5190,5191,5194],{"class":675,"line":741},[673,5192,5193],{"class":1257},"  ignis",[673,5195,1261],{"class":683},[673,5197,5198,5200,5202],{"class":675,"line":614},[673,5199,1327],{"class":1257},[673,5201,1276],{"class":683},[673,5203,5204],{"class":687}," nobbe\u002Fignis:latest\n",[673,5206,5207,5209],{"class":675,"line":776},[673,5208,1273],{"class":1257},[673,5210,1261],{"class":683},[673,5212,5213,5215,5217,5220],{"class":675,"line":782},[673,5214,1394],{"class":683},[673,5216,684],{"class":683},[673,5218,5219],{"class":687},"9898:8080",[673,5221,702],{"class":683},[673,5223,5224,5226],{"class":675,"line":827},[673,5225,1361],{"class":1257},[673,5227,1261],{"class":683},[673,5229,5230],{"class":675,"line":832},[673,5231,5232],{"class":737},"      # match these to your host user (run: id)\n",[673,5234,5235,5237],{"class":675,"line":838},[673,5236,1394],{"class":683},[673,5238,5239],{"class":687}," PUID=1000\n",[673,5241,5242,5244],{"class":675,"line":850},[673,5243,1394],{"class":683},[673,5245,5246],{"class":687}," PGID=1000\n",[673,5248,5249,5251],{"class":675,"line":855},[673,5250,1394],{"class":683},[673,5252,5253],{"class":687}," WS_ORIGINS=https:\u002F\u002Fobsidian.pafor.me\n",[673,5255,5256,5258],{"class":675,"line":861},[673,5257,1417],{"class":1257},[673,5259,1261],{"class":683},[673,5261,5262,5264],{"class":675,"line":883},[673,5263,1394],{"class":683},[673,5265,5266],{"class":687}," .\u002Fvaults:\u002Fvaults\n",[673,5268,5269,5271],{"class":675,"line":888},[673,5270,1394],{"class":683},[673,5272,5273],{"class":687}," .\u002Fdata:\u002Fapp\u002Fdata\n",[673,5275,5276,5278],{"class":675,"line":894},[673,5277,1394],{"class":683},[673,5279,5280],{"class":687}," obsidian-app:\u002Fapp\u002Fobsidian-app\n",[673,5282,5283,5285,5287],{"class":675,"line":908},[673,5284,1446],{"class":1257},[673,5286,1276],{"class":683},[673,5288,1451],{"class":687},[673,5290,5291],{"class":675,"line":913},[673,5292,773],{"emptyLinePlaceholder":772},[673,5294,5295,5297],{"class":675,"line":919},[673,5296,1478],{"class":1257},[673,5298,1261],{"class":683},[673,5300,5301,5304],{"class":675,"line":928},[673,5302,5303],{"class":1257},"  obsidian-app",[673,5305,1261],{"class":683},[455,5307,5308,5319,5332],{},[458,5309,5310,5311,5314,5315,5318],{},"Sử dụng cổng ",[645,5312,5313],{},"9898"," trên máy chủ host vì cổng ",[645,5316,5317],{},"8080"," rất dễ bị trùng lặp với các dịch vụ khác.",[458,5320,4377,5321,5324,5325,2559,5328,5331],{},[645,5322,5323],{},"id"," trên VPS để lấy thông số ",[645,5326,5327],{},"UID",[645,5329,5330],{},"GID"," của user trên máy chủ nhằm đảm bảo phân quyền ghi đọc chính xác.",[458,5333,5334,5335,5338],{},"Đặt ",[645,5336,5337],{},"WS_ORIGINS"," chỉ cho phép kết nối WebSocket từ đúng tên miền của bạn để tăng độ bảo mật.",[429,5340,5341,5342,1276],{},"Khởi chạy container ",[442,5343,4652],{},[665,5345,5347],{"className":667,"code":5346,"language":669,"meta":424,"style":424},"docker compose -f ignis-docker-compose.yml up -d\n",[645,5348,5349],{"__ignoreMap":424},[673,5350,5351,5353,5355,5357,5360,5362],{"class":675,"line":676},[673,5352,922],{"class":679},[673,5354,964],{"class":687},[673,5356,1550],{"class":687},[673,5358,5359],{"class":687}," ignis-docker-compose.yml",[673,5361,1561],{"class":687},[673,5363,1564],{"class":687},[429,5365,5366,5367,5370,5371,5374],{},"Khi bạn truy cập tên miền của mình trên trình duyệt web, giao diện ",[442,5368,5369],{},"'Vault Manager'"," sẽ hiện ra. Thư mục này hiện tại trống vì chưa có vault nào được liên kết. Ở phần tiếp theo, chúng ta sẽ cấu hình ",[442,5372,5373],{},"'Synch CLI'"," để đồng bộ dữ liệu từ vault từ xa về máy chủ.",[435,5376],{"src":5377,"alt":5378,"style":5379},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-vault-manager-empty.webp","Giao diện Vault Manager trống trong ứng dụng web Ignis","max-width: 466px; width: 100%; height: auto;",[586,5381,5383],{"id":5382},"giải-quyết-vấn-đề-firewall-của-docker","Giải quyết Vấn đề Firewall của Docker",[429,5385,5386,5387,5390,5391,1276],{},"Mặc định, Docker tự động chèn các quy tắc DNAT và FORWARD của riêng nó vào iptables, chuyển tiếp trực tiếp lưu lượng truy cập từ internet công cộng vào các cổng container đang hoạt động. Điều này bỏ qua hoàn toàn chuỗi bảo vệ ",[645,5388,5389],{},"INPUT"," thông thường của UFW hoặc iptables trên Ubuntu. Để chặn lưu lượng truy cập công cộng và giữ cho các container hoàn toàn riêng tư, hãy thêm các quy tắc sau vào ",[645,5392,5393],{},"iptables",[665,5395,5397],{"className":667,"code":5396,"language":669,"meta":424,"style":424},"# Chặn toàn bộ lưu lượng truy cập bên ngoài\nsudo iptables -I DOCKER-USER -i ext_if -j DROP \n\n# Chỉ cho phép lưu lượng truy cập từ địa chỉ IP riêng của client Cloudflare WARP\nsudo iptables -I DOCKER-USER -i ext_if -s 100.96.0.10 -j ACCEPT\n",[645,5398,5399,5404,5432,5436,5441],{"__ignoreMap":424},[673,5400,5401],{"class":675,"line":676},[673,5402,5403],{"class":737},"# Chặn toàn bộ lưu lượng truy cập bên ngoài\n",[673,5405,5406,5408,5411,5414,5417,5420,5423,5426,5429],{"class":675,"line":741},[673,5407,841],{"class":679},[673,5409,5410],{"class":687}," iptables",[673,5412,5413],{"class":687}," -I",[673,5415,5416],{"class":687}," DOCKER-USER",[673,5418,5419],{"class":687}," -i",[673,5421,5422],{"class":687}," ext_if",[673,5424,5425],{"class":687}," -j",[673,5427,5428],{"class":687}," DROP",[673,5430,5431],{"class":2013}," \n",[673,5433,5434],{"class":675,"line":614},[673,5435,773],{"emptyLinePlaceholder":772},[673,5437,5438],{"class":675,"line":776},[673,5439,5440],{"class":737},"# Chỉ cho phép lưu lượng truy cập từ địa chỉ IP riêng của client Cloudflare WARP\n",[673,5442,5443,5445,5447,5449,5451,5453,5455,5458,5461,5463],{"class":675,"line":782},[673,5444,841],{"class":679},[673,5446,5410],{"class":687},[673,5448,5413],{"class":687},[673,5450,5416],{"class":687},[673,5452,5419],{"class":687},[673,5454,5422],{"class":687},[673,5456,5457],{"class":687}," -s",[673,5459,5460],{"class":1311}," 100.96.0.10",[673,5462,5425],{"class":687},[673,5464,5465],{"class":687}," ACCEPT\n",[586,5467,5469],{"id":5468},"cấu-hình-synch-cli","Cấu hình Synch CLI",[429,5471,5472,5474],{},[442,5473,5100],{}," là công cụ dòng lệnh chạy headless (không giao diện), cho phép bạn đồng bộ hóa dữ liệu vault trực tiếp trên các máy chủ từ xa mà không cần cài đặt ứng dụng Obsidian hoàn chỉnh.",[429,5476,5477,5478,5480,5481,5484,5485,5488,5489,5492,5493,1081,5496,1081,5499,5502,5503,5506,5507,5510],{},"Build ",[442,5479,5100],{}," từ mã nguồn repository ",[645,5482,5483],{},"synch"," bạn đã clone. Quá trình build yêu cầu ",[442,5486,5487],{},"Node.js >= 22.5"," (vì CLI sử dụng thư viện ",[645,5490,5491],{},"node:sqlite"," và các API trình duyệt toàn cầu như ",[645,5494,5495],{},"fetch",[645,5497,5498],{},"WebSocket",[645,5500,5501],{},"WebCrypto",") và trình quản lý gói ",[442,5504,5505],{},"pnpm"," (repo là một pnpm workspace, sử dụng phiên bản ",[645,5508,5509],{},"pnpm@10.33.0","):",[665,5512,5514],{"className":667,"code":5513,"language":669,"meta":424,"style":424},"# Check versions\nnode --version   # must be >= 22.5\npnpm --version\n\n# In the repos root\npnpm install\n\n# Build the CLI bundle\npnpm -C apps\u002Fcli build\n\n# After a successful build you have `apps\u002Fcli\u002Fdist\u002Fsynch.js`. Make it executable and put it on your PATH\nchmod +x apps\u002Fcli\u002Fdist\u002Fsynch.js\nln -sf \"$PWD\u002Fapps\u002Fcli\u002Fdist\u002Fsynch.js\" \"$HOME\u002F.local\u002Fbin\u002Fsynch\"\n\n# Verification\nsynch --help\n",[645,5515,5516,5521,5532,5538,5542,5547,5554,5558,5563,5576,5580,5585,5596,5624,5628,5633],{"__ignoreMap":424},[673,5517,5518],{"class":675,"line":676},[673,5519,5520],{"class":737},"# Check versions\n",[673,5522,5523,5526,5529],{"class":675,"line":741},[673,5524,5525],{"class":679},"node",[673,5527,5528],{"class":687}," --version",[673,5530,5531],{"class":737},"   # must be >= 22.5\n",[673,5533,5534,5536],{"class":675,"line":614},[673,5535,5505],{"class":679},[673,5537,925],{"class":687},[673,5539,5540],{"class":675,"line":776},[673,5541,773],{"emptyLinePlaceholder":772},[673,5543,5544],{"class":675,"line":782},[673,5545,5546],{"class":737},"# In the repos root\n",[673,5548,5549,5551],{"class":675,"line":827},[673,5550,5505],{"class":679},[673,5552,5553],{"class":687}," install\n",[673,5555,5556],{"class":675,"line":832},[673,5557,773],{"emptyLinePlaceholder":772},[673,5559,5560],{"class":675,"line":838},[673,5561,5562],{"class":737},"# Build the CLI bundle\n",[673,5564,5565,5567,5570,5573],{"class":675,"line":850},[673,5566,5505],{"class":679},[673,5568,5569],{"class":687}," -C",[673,5571,5572],{"class":687}," apps\u002Fcli",[673,5574,5575],{"class":687}," build\n",[673,5577,5578],{"class":675,"line":855},[673,5579,773],{"emptyLinePlaceholder":772},[673,5581,5582],{"class":675,"line":861},[673,5583,5584],{"class":737},"# After a successful build you have `apps\u002Fcli\u002Fdist\u002Fsynch.js`. Make it executable and put it on your PATH\n",[673,5586,5587,5590,5593],{"class":675,"line":883},[673,5588,5589],{"class":679},"chmod",[673,5591,5592],{"class":687}," +x",[673,5594,5595],{"class":687}," apps\u002Fcli\u002Fdist\u002Fsynch.js\n",[673,5597,5598,5601,5604,5606,5609,5612,5614,5616,5619,5622],{"class":675,"line":888},[673,5599,5600],{"class":679},"ln",[673,5602,5603],{"class":687}," -sf",[673,5605,684],{"class":683},[673,5607,5608],{"class":2013},"$PWD",[673,5610,5611],{"class":687},"\u002Fapps\u002Fcli\u002Fdist\u002Fsynch.js",[673,5613,691],{"class":683},[673,5615,684],{"class":683},[673,5617,5618],{"class":2013},"$HOME",[673,5620,5621],{"class":687},"\u002F.local\u002Fbin\u002Fsynch",[673,5623,702],{"class":683},[673,5625,5626],{"class":675,"line":894},[673,5627,773],{"emptyLinePlaceholder":772},[673,5629,5630],{"class":675,"line":908},[673,5631,5632],{"class":737},"# Verification\n",[673,5634,5635,5637],{"class":675,"line":913},[673,5636,5483],{"class":679},[673,5638,5639],{"class":687}," --help\n",[429,5641,5642,5643,5646],{},"Vì Synch CLI đang chạy trên cùng một máy chủ VPS với máy chủ lưu trữ Synch, nó có thể tự động kết nối trực tiếp với server API cục bộ. Nếu bạn cấu hình một server khác, hãy chạy lệnh ",[645,5644,5645],{},"synch login --api-url \u003Cremote-synch-api-url>"," để chỉ định máy chủ API đích.",[429,5648,5649],{},[435,5650],{"alt":5651,"src":5652},"Chạy lệnh synch login với URL API tùy chỉnh trong terminal","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynch-login-api-url-terminal.webp",[429,5654,4377,5655,5658],{},[645,5656,5657],{},"synch login"," trong terminal của bạn, hệ thống sẽ trả về một đường link đăng nhập để xác thực:",[429,5660,5661],{},[435,5662],{"alt":5663,"src":5664},"Đầu ra terminal hiển thị URL xác thực cho Synch CLI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynch-login-auth-url-terminal.webp",[429,5666,5667],{},"Đăng nhập thông qua trình duyệt bằng tài khoản email trùng với tài khoản bạn đang sử dụng trên ứng dụng Obsidian desktop.",[429,5669,5670],{},[435,5671],{"alt":5672,"src":5673},"Đăng nhập web thành công để ủy quyền Synch CLI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynch-web-login-success.webp",[429,5675,4377,5676,5679],{},[645,5677,5678],{},"synch vault connect --vault ~\u002Fvaults\u002F\u003Cvaultname> --vault-id asadqe-7b29-4677-fsad-234asdafasd"," để liên kết thư mục vault cục bộ trên VPS với vault từ xa trên server của bạn.",[429,5681,5682,5683,5686,5687,5690,5691,5510],{},"ID của vault từ xa có thể được tìm thấy bằng cách vào plugin ",[442,5684,5685],{},"Synchrun"," trên máy tính và nhấn ",[442,5688,5689],{},"'Manage remote vaults'",". Hệ thống sẽ mở một trang web hiển thị danh sách các vault từ xa của bạn, mỗi vault đi kèm với một dãy GUID duy nhất (ví dụ: ",[645,5692,5693],{},"123e4567-e89b-12d3-a456-426614174000",[429,5695,5696,5701],{},[435,5697],{"src":5698,"alt":5699,"style":5700},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynchrun-manage-remote-vaults.webp","Quản lý kho ghi chú từ xa trong plugin Synchrun","max-width: 582px; width: 100%; height: auto;",[435,5702],{"alt":5703,"src":5704},"Định vị ID kho ghi chú từ xa duy nhất trong Synchrun","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynchrun-remote-vault-id.webp",[429,5706,5707,5708,5711],{},"Nhập mật khẩu vault khi được yêu cầu để hoàn tất liên kết. Sau khi kết nối thành công, chạy lệnh ",[645,5709,5710],{},"synch sync --vault ~\u002Fvaults\u002F\u003Cvault-name>"," to bắt đầu đồng bộ lần đầu tiên. Quá trình này có thể mất một thời gian tùy theo lượng file ghi chú của bạn.",[429,5713,5714],{},[435,5715],{"alt":5716,"src":5717},"Tiến trình đồng bộ kho ghi chú ban đầu trong Synch CLI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynch-cli-initial-sync-progress.webp",[429,5719,5720,5721,5724],{},"Để tự động hóa hoàn toàn việc này, hãy tạo và kích hoạt một dịch vụ systemd chạy lệnh ",[645,5722,5723],{},"synch watch"," liên tục trong nền, giúp đồng bộ hóa ghi chú ngay lập tức khi máy chủ khởi động:",[665,5726,5728],{"className":667,"code":5727,"language":669,"meta":424,"style":424},"sudo tee \u002Fetc\u002Fsystemd\u002Fsystem\u002Fsynch-watch.service \u003C\u003C'EOF'\n[Unit]\nDescription=Synch vault watcher\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nUser=\u003Cusername>\nExecStart=\u002Fhome\u002F\u003Cusername>\u002F.local\u002Fbin\u002Fsynch watch --vault \u002Fhome\u002F\u003Cusername>\u002Fvaults\u002F\u003Cvault-name>\nWorkingDirectory=\u002Fhome\u002F\u003Cusername>\u002Fvaults\nEnvironment=\"PATH=\u002Fhome\u002F\u003Cusername>\u002F.local\u002Fbin:\u002Fhome\u002F\u003Cusername>\u002F.cargo\u002Fbin:\u002Fusr\u002Flocal\u002Fsbin:\u002Fusr\u002Flocal\u002Fbin:\u002Fusr\u002Fsbin:\u002Fusr\u002Fbin:\u002Fsbin:\u002Fbin\"\nEnvironment=\"HOME=\u002Fhome\u002F\u003Cusername>\"\nRestart=always\nRestartSec=5\n\n[Install]\nWantedBy=multi-user.target\nEOF\nsudo systemctl daemon-reload\nsudo systemctl enable --now synch-watch.service\n",[645,5729,5730,5745,5750,5755,5760,5765,5769,5774,5779,5784,5789,5794,5799,5804,5809,5814,5818,5823,5828,5833,5842],{"__ignoreMap":424},[673,5731,5732,5734,5736,5739,5742],{"class":675,"line":676},[673,5733,841],{"class":679},[673,5735,815],{"class":687},[673,5737,5738],{"class":687}," \u002Fetc\u002Fsystemd\u002Fsystem\u002Fsynch-watch.service",[673,5740,5741],{"class":683}," \u003C\u003C",[673,5743,5744],{"class":683},"'EOF'\n",[673,5746,5747],{"class":675,"line":741},[673,5748,5749],{"class":687},"[Unit]\n",[673,5751,5752],{"class":675,"line":614},[673,5753,5754],{"class":687},"Description=Synch vault watcher\n",[673,5756,5757],{"class":675,"line":776},[673,5758,5759],{"class":687},"After=network-online.target\n",[673,5761,5762],{"class":675,"line":782},[673,5763,5764],{"class":687},"Wants=network-online.target\n",[673,5766,5767],{"class":675,"line":827},[673,5768,773],{"emptyLinePlaceholder":772},[673,5770,5771],{"class":675,"line":832},[673,5772,5773],{"class":687},"[Service]\n",[673,5775,5776],{"class":675,"line":838},[673,5777,5778],{"class":687},"Type=simple\n",[673,5780,5781],{"class":675,"line":850},[673,5782,5783],{"class":687},"User=\u003Cusername>\n",[673,5785,5786],{"class":675,"line":855},[673,5787,5788],{"class":687},"ExecStart=\u002Fhome\u002F\u003Cusername>\u002F.local\u002Fbin\u002Fsynch watch --vault \u002Fhome\u002F\u003Cusername>\u002Fvaults\u002F\u003Cvault-name>\n",[673,5790,5791],{"class":675,"line":861},[673,5792,5793],{"class":687},"WorkingDirectory=\u002Fhome\u002F\u003Cusername>\u002Fvaults\n",[673,5795,5796],{"class":675,"line":883},[673,5797,5798],{"class":687},"Environment=\"PATH=\u002Fhome\u002F\u003Cusername>\u002F.local\u002Fbin:\u002Fhome\u002F\u003Cusername>\u002F.cargo\u002Fbin:\u002Fusr\u002Flocal\u002Fsbin:\u002Fusr\u002Flocal\u002Fbin:\u002Fusr\u002Fsbin:\u002Fusr\u002Fbin:\u002Fsbin:\u002Fbin\"\n",[673,5800,5801],{"class":675,"line":888},[673,5802,5803],{"class":687},"Environment=\"HOME=\u002Fhome\u002F\u003Cusername>\"\n",[673,5805,5806],{"class":675,"line":894},[673,5807,5808],{"class":687},"Restart=always\n",[673,5810,5811],{"class":675,"line":908},[673,5812,5813],{"class":687},"RestartSec=5\n",[673,5815,5816],{"class":675,"line":913},[673,5817,773],{"emptyLinePlaceholder":772},[673,5819,5820],{"class":675,"line":919},[673,5821,5822],{"class":687},"[Install]\n",[673,5824,5825],{"class":675,"line":928},[673,5826,5827],{"class":687},"WantedBy=multi-user.target\n",[673,5829,5830],{"class":675,"line":933},[673,5831,5832],{"class":683},"EOF\n",[673,5834,5835,5837,5839],{"class":675,"line":948},[673,5836,841],{"class":679},[673,5838,899],{"class":687},[673,5840,5841],{"class":687}," daemon-reload\n",[673,5843,5844,5846,5848,5850,5853],{"class":675,"line":953},[673,5845,841],{"class":679},[673,5847,899],{"class":687},[673,5849,902],{"class":687},[673,5851,5852],{"class":687}," --now",[673,5854,5855],{"class":687}," synch-watch.service\n",[429,5857,5858,5859,5861],{},"Bây giờ, hãy mở tên miền ",[645,5860,5129],{}," trên trình duyệt. Bạn sẽ thấy giao diện sử dụng và bố cục layout gần như giống hệt với app Obsidian trên máy tính:",[435,5863],{"src":5864,"alt":5865,"style":5866},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-web-interface-desktop-view.webp","Giao diện web Ignis hiển thị kho ghi chú Obsidian trên màn hình máy tính","max-width: 593px; width: 100%; height: auto;",[429,5868,5869],{},"Bấm vào icon Cài đặt (Settings), bạn sẽ thấy hầu hết mọi cấu hình cốt lõi đều được giữ nguyên, chỉ có các community plugin là bạn cần cài đặt lại từ đầu:",[435,5871],{"src":5872,"alt":5873,"style":5874},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-settings-community-plugins.webp","Cài đặt plugin cộng đồng trong giao diện web Ignis","max-width: 597px; width: 100%; height: auto;",[429,5876,5877],{},"Để chạy thử nghiệm chu trình đồng bộ, bạn hãy thêm một ghi chú mới ngay trên trình duyệt:",[435,5879],{"src":5880,"alt":5881,"style":5874},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-create-new-note-web.webp","Tạo một ghi chú markdown mới thông qua giao diện web Ignis",[429,5883,5884,5885,599],{},"Ghi chú này sẽ ngay lập tức được đồng bộ ngược lại về ứng dụng Obsidian trên máy tính của bạn. Lưu ý rằng các thư mục trống sẽ không hiển thị trên giao diện của ",[442,5886,4652],{},[435,5888],{"src":5889,"alt":5890,"style":5891},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-desktop-synced-note.webp","Ghi chú mới tạo đã được đồng bộ thành công sang ứng dụng Obsidian máy tính","max-width: 502px; width: 100%; height: auto;",[429,5893,5894,5895,5897],{},"Giao diện hiển thị khi truy cập ",[645,5896,5129],{}," trên trình duyệt điện thoại di động:",[429,5899,5900,5905],{},[435,5901],{"src":5902,"alt":5903,"style":5904},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-mobile-view-sidebar.webp","Điều hướng thanh bên của ứng dụng web Ignis trên thiết bị di động","max-width: 269px; width: 100%; height: auto;",[435,5906],{"src":5907,"alt":5908,"style":5904},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-mobile-view-editor.webp","Trình chỉnh sửa ghi chú markdown của ứng dụng web Ignis trên thiết bị di động",[429,5910,5911,5912,5914,5915,5918],{},"Khi bạn xóa một ghi chú trên ",[442,5913,4652],{},", ghi chú đó sẽ được chuyển an toàn vào thư mục rác cục bộ ",[645,5916,5917],{},"~\u002Fvaults\u002F\u003Cvault-name>\u002F.trash"," để tránh mất mát dữ liệu ngoài ý muốn.",[447,5920,5922],{"id":5921},"lời-kết-cho-giải-pháp-tự-host-vault-obsidian","Lời kết cho giải pháp tự host Vault Obsidian",[429,5924,5925,5926,2559,5928,5930,5931,5933],{},"Sự kết hợp giữa ",[442,5927,4643],{},[442,5929,4652],{}," giúp vault Obsidian của bạn luôn khả dụng trên mọi thiết bị, chạy hoàn toàn trên hạ tầng VPS do chính bạn kiểm soát. Việc đặt các dịch vụ này đằng sau mạng riêng ảo ",[442,5932,3993],{}," đem lại một hàng rào bảo mật tuyệt đối, ngăn chặn mọi nỗ lực xâm nhập từ internet công cộng.",[429,5935,5936,5937,5939],{},"Tất nhiên, ",[442,5938,4652],{}," không được thiết kế để thay thế hoàn toàn ứng dụng Obsidian gốc trên máy tính. Nó đóng vai trò như một giải pháp cứu cánh tạm thời, giúp bạn đọc và sửa ghi chú nhanh chóng qua bất kỳ trình duyệt nào khi không mang theo máy tính cá nhân. Đối với việc soạn thảo tài liệu lâu dài hay quản lý vault chuyên sâu, ứng dụng gốc trên máy tính vẫn là lựa chọn đem lại trải nghiệm tốt nhất.",[429,5941,5942,5943,5945],{},"Do cơ chế mã hóa đầu cuối cực kỳ mạnh mẽ của Synch, mật khẩu vault từ xa của bạn phải đủ phức tạp để tránh bị tấn công brute-force. Việc ghi nhớ mật khẩu này là vô cùng quan trọng vì server không hề lưu trữ ",[442,5944,4711],{}," giải mã; nếu quên mật khẩu, dữ liệu ghi chú của bạn sẽ vĩnh viễn không thể khôi phục. Ngoài ra, hãy chú ý bảo mật VPS của bạn thật tốt cùng với các bản snapshot và backup định kỳ.",[429,5947,5948,5949,5951],{},"Mặc dù tính năng lưu lịch sử phiên bản đã mã hóa và khôi phục file đã xóa của ",[442,5950,4643],{}," bảo vệ bạn khỏi hầu hết rủi ro mất dữ liệu, việc lưu trữ thêm một bản backup độc lập của vault Obsidian ở một nơi khác vẫn luôn là điều cần thiết.",[447,5953,5955],{"id":5954},"references","References",[455,5957,5958,5965,5972],{},[458,5959,5960],{},[569,5961,5964],{"href":5962,"rel":5963},"https:\u002F\u002Fsynch.run\u002Fself-hosting-docker\u002F",[1654],"Synch Deploy with Docker Compose",[458,5966,5967],{},[569,5968,5971],{"href":5969,"rel":5970},"https:\u002F\u002Fignis.thiefling.com\u002Fdocs\u002Fserver\u002Fdeploy\u002F",[1654],"Ignis Deploy with Docker",[458,5973,5974],{},[569,5975,5978],{"href":5976,"rel":5977},"https:\u002F\u002Fsynch.run\u002Fblog\u002Fencryption-and-decryption\u002F",[1654],"How does end-to-end encryption work in Synch?",[2645,5980,5981],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":424,"searchDepth":741,"depth":614,"links":5983},[5984,5993,6002,6003],{"id":4683,"depth":741,"text":4684,"children":5985},[5986,5990],{"id":4725,"depth":614,"text":4726,"children":5987},[5988,5989],{"id":4729,"depth":776,"text":4730},{"id":4744,"depth":776,"text":4745},{"id":4951,"depth":614,"text":4952,"children":5991},[5992],{"id":4955,"depth":776,"text":4956},{"id":5064,"depth":741,"text":5065,"children":5994},[5995],{"id":5086,"depth":614,"text":5087,"children":5996},[5997,5998,5999,6000,6001],{"id":5114,"depth":776,"text":5115},{"id":5123,"depth":776,"text":4841},{"id":5169,"depth":776,"text":5170},{"id":5382,"depth":776,"text":5383},{"id":5468,"depth":776,"text":5469},{"id":5921,"depth":741,"text":5922},{"id":5954,"depth":741,"text":5955},[6005],"productivity","2026-09-15","Học cách đồng bộ hóa an toàn vault Obsidian qua các thiết bị bằng cách tự host Synch và Ignis trong mạng riêng Cloudflare Zero Trust cực kỳ bảo mật.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002FVI-Sync-Obsidian-Across-Devices.webp","Sơ đồ kiến trúc đồng bộ hóa an toàn các vault Obsidian giữa nhiều thiết bị sử dụng Synch tự host và Ignis trong mạng Cloudflare Zero Trust bảo mật",{"schemaOrg":6011,"robots":2709,"sitemap":6014},[6012,6013],{"@type":4615,"headline":4625,"description":6007,"image":6008},{"@type":2691,"name":4625,"description":6007,"image":6008},{"lastmod":6015},"2026-09-16",{"title":6017,"description":6007,"ogTitle":4625,"ogDescription":6007,"twitterTitle":4625,"twitterDescription":6007},"Đồng bộ Obsidian tự host an toàn với Synch và Ignis","vi\u002Farticle\u002Fsync-obsidian-across-devices",[6020,6021,6022,6023],"Self-hosting","Obsidian","Đồng bộ","Zero Trust","384lhiI8EJgp7zpAfkzfVEbp3fnozc75rkPBSiIpG_M",[6026,7236,7237],{"id":6027,"title":6028,"author":424,"body":6029,"category":7200,"date":7202,"description":7203,"extension":2683,"image":7204,"imageAlt":7205,"isPublished":772,"meta":7206,"minRead":894,"navigation":772,"path":355,"seo":7230,"stem":7232,"tags":7233,"updatedAt":2720,"__hash__":7235},"article\u002Fvi\u002Farticle\u002Fbringing-buzz-to-deepseek-harness.md","Kết nối DeepSeek Harness với Buzz qua Gateway Nostr",{"type":426,"value":6030,"toc":7184},[6031,6037,6057,6060,6063,6067,6073,6115,6118,6175,6179,6185,6461,6464,6468,6472,6478,6482,6496,6500,6509,6554,6561,6565,6568,6600,6604,6609,6650,6658,6664,6672,6678,6707,6720,6724,6733,6757,6778,6819,6826,6831,6837,6844,6850,6855,6862,6876,6882,6891,6926,6929,6935,6942,6948,6952,6955,7105,7109,7143,7147,7153,7155,7181],[429,6032,6033],{},[435,6034],{"alt":6035,"src":6036},"Tổng quan về cổng tin nhắn DeepSeek Harness kết nối với kênh Block Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-nostr-gateway-overview.webp",[429,6038,6039,6040,6047,6048,6052,6053,599],{},"Plugin DeepSeek Harness (DSH), ",[442,6041,6042],{},[569,6043,6046],{"href":6044,"rel":6045},"https:\u002F\u002Fgithub.com\u002Fa792883583\u002Fdsh-message-gateway",[1654],"dsh-message-gateway",", mở rộng trợ lý DeepSeek Harness tới nhiều nền tảng nhắn tin phổ biến như Discord, Telegram và WeChat. Kho lưu trữ plugin này đã được fork và phát triển mở rộng để đưa nền tảng ",[442,6049,6050],{},[569,6051,423],{"href":383}," vào danh sách hỗ trợ. Kho lưu trữ được fork hiện có sẵn công khai trên GitHub tại ",[569,6054,6055],{"href":6055,"rel":6056},"https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fdsh-message-gateway",[1654],[574,6058],{"description":2682,"image":2684,"image-alt":2685,"label":6059,"min-read":4855,"title":423,"to":383},"Hướng dẫn điều kiện tiên quyết",[429,6061,6062],{},"Trợ lý DSH tham gia vào relay Buzz như một thành viên chính thức, nhận tin nhắn trực tiếp (DM) cũng như tin nhắn trong các kênh mà nó được @mention, và phản hồi thông qua cùng một quy trình agent pipeline theo từng phiên trò chuyện tương tự giao diện Web.",[447,6064,6066],{"id":6065},"kiến-trúc-của-plugin-dsh-message-gateway","Kiến trúc của Plugin dsh-message-gateway",[429,6068,6069,6070,6072],{},"Kiến trúc của plugin ",[442,6071,6046],{}," được chia làm hai phần cốt lõi:",[455,6074,6075,6105],{},[458,6076,6077,6080,6081,6084,6085,6088,6089,6092,6093,6096,6097,6100,6101,6104],{},[442,6078,6079],{},"Host"," (môi trường Node): ",[645,6082,6083],{},"gateway-store"," (quản lý thông tin xác thực tại ",[645,6086,6087],{},"~\u002F.dsh\u002Fgateway.json","), ",[645,6090,6091],{},"platforms.ts"," (định nghĩa nền tảng và kiểm tra kết nối), ",[645,6094,6095],{},"routes.ts"," (các endpoint ",[645,6098,6099],{},"\u002Fgateway\u002F*","), và ",[645,6102,6103],{},"bridge-manager.ts"," (các cầu nối thường trú: quản lý phiên tác nhân độc lập cho từng cuộc trò chuyện và luồng phản hồi streaming).",[458,6106,6107,6110,6111,6114],{},[442,6108,6109],{},"Client"," (phía trình duyệt): trang \"",[442,6112,6113],{},"Message platforms","\" ở thanh bên nơi bạn lưu thông tin đăng nhập, kiểm tra kết nối mạng và giám sát trạng thái hoạt động.",[429,6116,6117],{},"Việc tích hợp một nền tảng mới bao gồm các bước sau:",[591,6119,6120,6137,6151],{},[458,6121,6122,6125,6126,6129,6130,6133,6134,599],{},[442,6123,6124],{},"Lớp cầu nối (bridge class)",": cung cấp các phương thức ",[645,6127,6128],{},"start\u002Fstop\u002Fstatus"," kèm theo một hàm gọi lại (callback) ",[645,6131,6132],{},"onText(text, frame)",", tương tự mẫu thiết kế của ",[645,6135,6136],{},"wecom-bridge.ts",[458,6138,6139,6142,6143,6146,6147,6150],{},[442,6140,6141],{},"Đấu nối vào bridge-manager",": tái sử dụng pipeline theo từng đoạn chat sẵn có (",[645,6144,6145],{},"ensureAgentForKey"," + ",[645,6148,6149],{},"pendingMap",") và gắn kết luồng trả lời của nền tảng vào.",[458,6152,6153,6156,6157,2559,6160,1077,6163,6166,6167,6170,6171,6174],{},[442,6154,6155],{},"Lưu trữ và định tuyến",": trong ",[645,6158,6159],{},"\u002Fgateway\u002Fsave",[645,6161,6162],{},"\u002Fgateway\u002Fdelete",[442,6164,6165],{},"lưu thông tin đăng nhập sẽ khởi động cầu nối, xóa sẽ dừng cầu nối"," — kèm theo cờ ",[645,6168,6169],{},"autoStartXxx"," để ",[645,6172,6173],{},"dsh web"," tự động kết nối lại khi hệ thống khởi động.",[447,6176,6178],{"id":6177},"hiện-thực-cầu-nối-buzz-giao-thức-nostr-vòng-đời-sự-kiện","Hiện thực Cầu nối Buzz: Giao thức Nostr & Vòng đời sự kiện",[429,6180,6181,6184],{},[442,6182,6183],{},"DeepSeek Harness"," đã được sử dụng trực tiếp để hiện thực hóa cầu nối Buzz. Quá trình triển khai tuân thủ nghiêm ngặt các đặc tả kỹ thuật của giao thức Nostr sau:",[6186,6187,6188,6203],"table",{},[6189,6190,6191],"thead",{},[6192,6193,6194,6200],"tr",{},[6195,6196,6197],"th",{},[442,6198,6199],{},"Hạng mục",[6195,6201,6202],{},"Đặc tả chi tiết",[6204,6205,6206,6228,6246,6274,6292,6316,6339,6363,6376,6389,6408,6425,6439],"tbody",{},[6192,6207,6208,6214],{},[6209,6210,6211],"td",{},[442,6212,6213],{},"Giao vận (Transport)",[6209,6215,6216,6217,6220,6221,6224,6225],{},"Một kết nối WebSocket duy nhất có xác thực NIP-42; mặc định ",[645,6218,6219],{},"ws:\u002F\u002Flocalhost:3000","; ",[645,6222,6223],{},"http(s):\u002F\u002F"," được chuẩn hóa thành ",[645,6226,6227],{},"ws(s):\u002F\u002F",[6192,6229,6230,6235],{},[6209,6231,6232],{},[442,6233,6234],{},"Xác thực (Auth)",[6209,6236,6237,6238,6241,6242,6245],{},"Sự kiện AUTH ",[645,6239,6240],{},"kind 22242",", gắn thẻ ",[645,6243,6244],{},"[[\"relay\", url], [\"challenge\", challenge]]",", nội dung trống, ký bằng khóa riêng của tác nhân",[6192,6247,6248,6253],{},[6209,6249,6250],{},[442,6251,6252],{},"Đăng ký nhận tin",[6209,6254,6255,1077,6258,6261,6262,6265,6266,6269,6270,6273],{},[442,6256,6257],{},"Theo từng kênh",[645,6259,6260],{},"REQ {\"kinds\":[9], \"#h\":[\u003Cuuid>]}"," — một REQ cho mỗi kênh. Lệnh REQ toàn cục ",[645,6263,6264],{},"kinds:[9]"," nhận EOSE nhưng không phân phối sự kiện; bộ lọc ",[645,6267,6268],{},"#h"," đa giá trị ",[442,6271,6272],{},"không"," chạy",[6192,6275,6276,6281],{},[6209,6277,6278],{},[442,6279,6280],{},"Khám phá (Discovery)",[6209,6282,6283,6284,6287,6288,6291],{},"Truy vấn lịch sử ",[645,6285,6286],{},"REQ {kinds:[39000]}"," để lấy metadata của kênh (",[645,6289,6290],{},"type == \"dm\""," đánh dấu kênh tin nhắn trực tiếp)",[6192,6293,6294,6299],{},[6209,6295,6296],{},[442,6297,6298],{},"Tư cách thành viên",[6209,6300,6301,6302,6305,6306,6308,6309,6312,6313],{},"Lắng nghe trực tiếp ",[645,6303,6304],{},"REQ {kinds:[44100,44101], \"#p\":[pubkey của ta], since: now-60s}"," — 44100 = thêm, 44101 = xóa (chứa ",[645,6307,429],{},"+",[645,6310,6311],{},"h","); cập nhật gói đăng ký ",[442,6314,6315],{},"không cần kết nối lại",[6192,6317,6318,6323],{},[6209,6319,6320],{},[442,6321,6322],{},"Sự kiện trò chuyện",[6209,6324,6325,6328,6329,6332,6333,1081,6336],{},[645,6326,6327],{},"kind 9"," với thẻ ",[645,6330,6331],{},"[\"h\", channel]",", tùy chọn ",[645,6334,6335],{},"[\"e\", replyTo]",[645,6337,6338],{},"[\"p\", mention]",[6192,6340,6341,6346],{},[6209,6342,6343],{},[442,6344,6345],{},"Chỉnh sửa tại chỗ",[6209,6347,6348,6351,6352,6146,6354,6357,6358,3744,6360,6362],{},[645,6349,6350],{},"kind 40003"," với ",[645,6353,6311],{},[645,6355,6356],{},"e","→mục tiêu; thay thế nội dung; giới hạn relay 64 KB → giữ tải ≤ 60.000 B; phản hồi dài được cắt mảnh — mảnh 0 ghi đè, phần dư nối tiếp dạng luồng ",[645,6359,6327],{},[645,6361,6356],{},"→gốc)",[6192,6364,6365,6370],{},[6209,6366,6367],{},[442,6368,6369],{},"Khung CLOSED",[6209,6371,6372,6375],{},[645,6373,6374],{},"auth-required"," trước AUTH là khởi động bình thường (hoàn tất AUTH, mở lại đăng ký); sau AUTH → thử lại có giới hạn (3 lần, lùi 0\u002F1\u002F2 giây); kết nối lại sẽ dựng lại toàn bộ trạng thái",[6192,6377,6378,6383],{},[6209,6379,6380],{},[442,6381,6382],{},"Giới hạn relay",[6209,6384,6385,6386],{},"Tối đa 2000 sự kiện lịch sử trên mỗi đăng ký, sắp xếp mới nhất trước ngay cả khi sử dụng bộ lọc ",[645,6387,6388],{},"since",[6192,6390,6391,6396],{},[6209,6392,6393],{},[442,6394,6395],{},"Kiểm soát mention",[6209,6397,6398,6399,6401,6402,6404,6405,6407],{},"Chỉ xử lý ",[645,6400,6327],{}," gửi đến khi: (a) thẻ ",[645,6403,429],{}," có pubkey của ta, (b) kênh là DM, hoặc (c) gốc ",[645,6406,6356],{}," là sự kiện của chính ta. Bỏ qua pubkey của bản thân (chống lặp vô tận)",[6192,6409,6410,6415],{},[6209,6411,6412],{},[442,6413,6414],{},"Mention gửi đi",[6209,6416,6417,6418,6421,6422,6424],{},"Văn bản gửi đi được xuất bản nguyên văn — relay không kiểm tra cú pháp ",[645,6419,6420],{},"@","; thẻ ",[645,6423,429],{}," mang tác giả nguồn cùng tối đa 7 pubkey khác được nhắc đến (tổng tối đa 8)",[6192,6426,6427,6432],{},[6209,6428,6429],{},[442,6430,6431],{},"Tin nhắn riêng (DM)",[6209,6433,6434,6435,6438],{},"Kênh văn bản thuần túy trong phạm vi relay (metadata ",[645,6436,6437],{},"type: \"dm\"",") — không áp dụng mã hóa NIP-04\u002F44 trong cầu nối này",[6192,6440,6441,6446],{},[6209,6442,6443],{},[442,6444,6445],{},"Tệp đính kèm (Đến)",[6209,6447,6448,6449,3744,6452,1081,6454,1081,6457,6460],{},"NIP-92 ",[645,6450,6451],{},"imeta",[645,6453,4460],{},[645,6455,6456],{},"sha256",[645,6458,6459],{},"m",") → tải xuống qua http(s), kiểm tra mã băm SHA-256, giới hạn 20 MB, tối đa 4 tệp\u002Ftin; hình ảnh gửi đi hiện không được hỗ trợ",[429,6462,6463],{},"Sơ đồ dưới đây minh họa toàn bộ quy trình khởi tạo (bootstrap) kết nối của cầu nối Buzz:",[435,6465],{"src":6466,"alt":6467},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-bootstrap.webp","Sơ đồ trình tự minh họa quy trình khởi tạo bootstrap và xác thực NIP-42 của cầu nối Buzz",[547,6469,6471],{"id":6470},"truyền-phát-thời-gian-thực-thông-qua-chỉnh-sửa-tại-chỗ-nostr-kind-40003","Truyền phát thời gian thực thông qua chỉnh sửa tại chỗ Nostr (Kind 40003)",[429,6473,6474,6475,1276],{},"Do Nostr không có chỉ báo đang gõ tin nhắn tự nhiên và các sự kiện đều là dạng ghi tiếp (append-only), cầu nối Buzz ",[442,6476,6477],{},"mô phỏng hiệu ứng truyền phát streaming bằng cách chỉnh sửa tại chỗ",[435,6479],{"src":6480,"alt":6481},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-reply.webp","Sơ đồ luồng chỉnh sửa tại chỗ mô phỏng phản hồi truyền phát streaming với sự kiện kind 40003",[455,6483,6484],{},[458,6485,6486],{},[6487,6488,6489,6490,6492,6493,6495],"em",{},"Cầu nối Buzz xuất bản trước một sự kiện giữ chỗ ",[645,6491,6327],{},", sau đó liên tục ghi đè nội dung theo tốc độ định sẵn bằng các sự kiện chỉnh sửa tại chỗ ",[645,6494,6350],{},", và thực hiện lần chỉnh sửa cuối cùng khi tác nhân hoàn tất phản hồi. Điều này tái hiện chính xác mô hình \"gửi rồi sửa\" đã được kiểm chứng trên các cầu nối Telegram và Discord.",[547,6497,6499],{"id":6498},"kết-nối-workspace-của-deepseek-harness-thông-qua-lệnh-chat","Kết nối Workspace của DeepSeek Harness thông qua lệnh chat",[429,6501,6502,6503,3744,6506,5510],{},"Tính năng \"Workspaces\" trên giao diện Web DSH được quản lý bởi dịch vụ nền tảng ",[645,6504,6505],{},"workspaceRegistry",[645,6507,6508],{},"@deepseek-ai\u002Fdsh-workspace",[665,6510,6514],{"className":6511,"code":6512,"language":6513,"meta":424,"style":424},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const existing = await ctx.workspaceRegistry.resolveByPath(request.path);\n","typescript",[645,6515,6516],{"__ignoreMap":424},[673,6517,6518,6521,6524,6527,6531,6534,6536,6538,6540,6543,6546,6548,6551],{"class":675,"line":676},[673,6519,6520],{"class":1279},"const",[673,6522,6523],{"class":2013}," existing ",[673,6525,6526],{"class":683},"=",[673,6528,6530],{"class":6529},"s7zQu"," await",[673,6532,6533],{"class":2013}," ctx",[673,6535,599],{"class":683},[673,6537,6505],{"class":2013},[673,6539,599],{"class":683},[673,6541,6542],{"class":785},"resolveByPath",[673,6544,6545],{"class":2013},"(request",[673,6547,599],{"class":683},[673,6549,6550],{"class":2013},"path)",[673,6552,6553],{"class":683},";\n",[429,6555,6556,6557,6560],{},"Cầu nối Buzz cung cấp lệnh trò chuyện ",[645,6558,6559],{},"\u002Fworkspace \u003Cthư mục>",", cho phép đăng ký một thư mục sẵn có vào DSH. Mọi phiên làm việc mới được tạo qua gateway sẽ tự động gắn vào thư mục này và xuất hiện đồng bộ trên giao diện Web.",[435,6562],{"src":6563,"alt":6564},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-workspace.webp","Kiến trúc đăng ký workspace DeepSeek Harness từ các lệnh trò chuyện qua gateway",[429,6566,6567],{},"Ba lưu ý quan trọng về mặt thiết kế:",[455,6569,6570,6580,6590],{},[458,6571,6572,6575,6576,6579],{},[442,6573,6574],{},"Đổi thư mục = Tạo phiên mới."," Tham số ",[645,6577,6578],{},"cwd"," được ghi cố định vào tiêu đề phiên khi khởi tạo và không thể chỉnh sửa về sau.",[458,6581,6582,6585,6586,6589],{},[442,6583,6584],{},"Thư mục bắt buộc phải tồn tại."," Hàm ",[645,6587,6588],{},"create"," sẽ từ chối các đường dẫn không có thực trên ổ đĩa.",[458,6591,6592,6595,6596,6599],{},[442,6593,6594],{},"Lệnh có yêu cầu bảo mật cao."," Mỗi phiên làm việc đều hoạt động theo chính sách ",[442,6597,6598],{},"auto-approve"," (tự động phê duyệt), cấp quyền truy cập tệp trong thư mục mục tiêu.",[447,6601,6603],{"id":6602},"hướng-dẫn-cài-đặt-và-cấu-hình-từng-bước","Hướng dẫn cài đặt và cấu hình từng bước",[591,6605,6606],{},[458,6607,6608],{},"Chạy các lệnh sau trong cửa sổ dòng lệnh terminal của bạn:",[665,6610,6612],{"className":667,"code":6611,"language":669,"meta":424,"style":424},"dsh plugin --profile web add https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fdsh-message-gateway.git\n\n# Start DSH web\ndsh web\n",[645,6613,6614,6634,6638,6643],{"__ignoreMap":424},[673,6615,6616,6619,6622,6625,6628,6631],{"class":675,"line":676},[673,6617,6618],{"class":679},"dsh",[673,6620,6621],{"class":687}," plugin",[673,6623,6624],{"class":687}," --profile",[673,6626,6627],{"class":687}," web",[673,6629,6630],{"class":687}," add",[673,6632,6633],{"class":687}," https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fdsh-message-gateway.git\n",[673,6635,6636],{"class":675,"line":741},[673,6637,773],{"emptyLinePlaceholder":772},[673,6639,6640],{"class":675,"line":614},[673,6641,6642],{"class":737},"# Start DSH web\n",[673,6644,6645,6647],{"class":675,"line":776},[673,6646,6618],{"class":679},[673,6648,6649],{"class":687}," web\n",[591,6651,6652],{"start":741},[458,6653,6654,6655,6657],{},"Khi giao diện Web DSH mở ra trong trình duyệt web, nhấp vào biểu tượng \"",[442,6656,6113],{},"\":",[429,6659,6660],{},[435,6661],{"alt":6662,"src":6663},"Thanh bên giao diện Web DeepSeek Harness làm nổi bật menu cấu hình Message platforms","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-web-ui-message-platforms-sidebar-icon.webp",[591,6665,6666],{"start":614},[458,6667,6668,6669,6671],{},"Chọn mục \"",[442,6670,444],{},"\" ở bảng điều khiển bên trái:",[429,6673,6674],{},[435,6675],{"alt":6676,"src":6677},"Bảng cài đặt cấu hình cầu nối Buzz trong cổng tin nhắn DeepSeek Harness","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-message-gateway-buzz-config-panel.webp",[591,6679,6680,6691,6701],{"start":776},[458,6681,6682,6683,6686,6687,6690],{},"Nhấp vào \"",[442,6684,6685],{},"Generate keypair","\" để tạo cặp khóa Nostr mới. Hãy sao chép khóa công khai ",[645,6688,6689],{},"npub"," vào nơi an toàn.",[458,6692,6693,6694,2559,6697,6700],{},"Điền thông tin vào ô ",[442,6695,6696],{},"Relay URL",[442,6698,6699],{},"Channels"," (danh sách UUID các kênh cho phép đăng ký).",[458,6702,6703,6704,6706],{},"Nhấp vào nút \"",[442,6705,3337],{},"\".",[429,6708,6709,6710,6713,6714,6717,6718,599],{},"Lưu biểu mẫu sẽ lưu trữ thông tin đăng nhập và ",[442,6711,6712],{},"kích hoạt cầu nối khởi chạy",". Khóa bí mật ",[645,6715,6716],{},"nsec"," được coi là thông tin mật tuyệt đối và chỉ lưu trữ duy nhất trong tệp ",[645,6719,6087],{},[547,6721,6723],{"id":6722},"đăng-ký-cặp-khóa-tác-nhân-lên-buzz-nostr-relay","Đăng ký cặp khóa tác nhân lên Buzz Nostr Relay",[429,6725,6726,6729,6730,6732],{},[442,6727,6728],{},"Thêm trợ lý DSH vào relay với tư cách là một thành viên."," Sử dụng khóa công khai ",[645,6731,6689],{}," vừa tạo ở bước trên:",[665,6734,6736],{"className":667,"code":6735,"language":669,"meta":424,"style":424},"docker compose exec relay buzz-admin add-member --pubkey npub123123123\n",[645,6737,6738],{"__ignoreMap":424},[673,6739,6740,6742,6744,6746,6748,6750,6752,6754],{"class":675,"line":676},[673,6741,922],{"class":679},[673,6743,964],{"class":687},[673,6745,1691],{"class":687},[673,6747,1694],{"class":687},[673,6749,1697],{"class":687},[673,6751,1700],{"class":687},[673,6753,1703],{"class":687},[673,6755,6756],{"class":687}," npub123123123\n",[429,6758,6759,6762,6763,6765,6766,6769,6770,6773,6774,6777],{},[442,6760,6761],{},"Thêm trợ lý DSH vào một kênh cụ thể."," Việc thêm thành viên vào relay chỉ mới đưa tác nhân lên máy chủ, nó sẽ chưa tự động hiển thị hay tìm kiếm được trong các kênh. Khi thực hiện bước này bằng công cụ ",[645,6764,1833],{},", cần lưu ý rằng tham số ",[645,6767,6768],{},"--pubkey"," phải ở định dạng ",[442,6771,6772],{},"HEX",", không phải npub (lệnh ",[645,6775,6776],{},"buzz-admin add-member"," trước đó sẽ in ra khóa HEX tương ứng):",[665,6779,6781],{"className":667,"code":6780,"language":669,"meta":424,"style":424},"buzz channels add-member --channel \u003CCHANNEL_UUID> --pubkey \u003CAGENT_HEX> --role member\n",[645,6782,6783],{"__ignoreMap":424},[673,6784,6785,6787,6789,6791,6793,6795,6797,6799,6801,6803,6805,6808,6811,6813,6816],{"class":675,"line":676},[673,6786,2065],{"class":679},[673,6788,2068],{"class":687},[673,6790,1700],{"class":687},[673,6792,2120],{"class":687},[673,6794,2336],{"class":683},[673,6796,2339],{"class":687},[673,6798,2342],{"class":2013},[673,6800,2017],{"class":683},[673,6802,1703],{"class":687},[673,6804,2336],{"class":683},[673,6806,6807],{"class":687},"AGENT_HE",[673,6809,6810],{"class":2013},"X",[673,6812,2017],{"class":683},[673,6814,6815],{"class":687}," --role",[673,6817,6818],{"class":687}," member\n",[574,6820],{"description":6821,"image":2684,"image-alt":2685,"label":6822,"min-read":6823,"title":6824,"to":6825},"Hướng dẫn từng bước để cài đặt và định cấu hình buzz-cli nhằm quản lý các kênh Nostr, khóa thành viên và quyền của tác nhân AI.","Hướng dẫn CLI","5","Cách cài đặt và sử dụng buzz-cli","\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues#install-buzz-cli",[429,6827,6828,6829,1276],{},"Cập nhật hồ sơ của trợ lý DSH trên Nostr relay thành một tên hiển thị trực quan và thân thiện hơn bằng ",[645,6830,1833],{},[429,6832,6833],{},[435,6834],{"alt":6835,"src":6836},"Cập nhật tên hiển thị của trợ lý DeepSeek Harness trên Nostr relay bằng buzz-cli","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-assistant-buzz-cli-profile-update.webp",[429,6838,6839,6840,6843],{},"Gửi một lời chào ",[442,6841,6842],{},"Wave"," (hành động vẫy tay chào qua DM của Buzz) tới trợ lý DSH. Phản hồi gửi ngược lại báo hiệu hệ thống đã vận hành trơn tru:",[429,6845,6846],{},[435,6847],{"alt":6848,"src":6849},"Kiểm tra kết nối bằng cách gửi tin nhắn Wave dạng DM tới trợ lý DeepSeek Harness trong Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-dm-wave-greeting-reply.webp",[429,6851,6852],{},[6487,6853,6854],{},"Gửi tin nhắn Wave dạng DM tới trợ lý DSH — cầu nối phản hồi ngay lập tức.",[547,6856,6858,6859],{"id":6857},"cho-phép-mở-quyền-thư-mục-cục-bộ-với-lệnh-workspace","Cho phép mở quyền thư mục cục bộ với lệnh ",[645,6860,6861],{},"\u002Fworkspace",[429,6863,6864,6865,6868,6869,6872,6873,6875],{},"Do thiết lập ",[645,6866,6867],{},"allowWorkspace"," được đặt mặc định là ",[645,6870,6871],{},"false"," để bảo vệ an toàn, lệnh ",[645,6874,6861],{}," ban đầu sẽ bị từ chối:",[429,6877,6878],{},[435,6879],{"alt":6880,"src":6881},"Thông báo lỗi lệnh workspace bị từ chối khi tùy chọn allowWorkspace đang bị tắt","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-workspace-command-rejected-error.webp",[429,6883,6884,6885,6888,6889,1276],{},"Bật tính năng này trong tệp ",[645,6886,6887],{},"~\u002F.dsh\u002Fprofiles\u002Fweb\u002Fcordis.patch.yml",", sau đó khởi động lại ",[645,6890,6173],{},[665,6892,6894],{"className":1164,"code":6893,"language":1166,"meta":424,"style":424},"- id: ui-message-gateway\n  config:\n    allowWorkspace: true\n",[645,6895,6896,6909,6916],{"__ignoreMap":424},[673,6897,6898,6901,6904,6906],{"class":675,"line":676},[673,6899,6900],{"class":683},"-",[673,6902,6903],{"class":1257}," id",[673,6905,1276],{"class":683},[673,6907,6908],{"class":687}," ui-message-gateway\n",[673,6910,6911,6914],{"class":675,"line":741},[673,6912,6913],{"class":1257},"  config",[673,6915,1261],{"class":683},[673,6917,6918,6921,6923],{"class":675,"line":614},[673,6919,6920],{"class":1257},"    allowWorkspace",[673,6922,1276],{"class":683},[673,6924,2234],{"class":6925},"sfNiH",[429,6927,6928],{},"Sau khi khởi động lại:",[429,6930,6931],{},[435,6932],{"alt":6933,"src":6934},"Thông báo xác nhận thành công sau khi thực thi lệnh đăng ký workspace trong Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-workspace-command-success-confirmation.webp",[429,6936,6937,6938,6941],{},"Điểm cần nhớ: cấu hình mặc định này giả định thư mục không gian làm việc (",[645,6939,6940],{},"TechVoyage"," trong hình minh họa) nằm trong thư mục gốc của người dùng hiện tại. Nếu nằm ở vị trí khác, hãy điền đầy đủ đường dẫn tuyệt đối. Bất kỳ phiên làm việc mới nào được tạo dưới workspace này qua Buzz cũng sẽ đồng bộ hiển thị trên giao diện Web của DeepSeek Harness.",[429,6943,6944],{},[435,6945],{"alt":6946,"src":6947},"Giao diện Web DeepSeek Harness hiển thị phiên làm việc được đồng bộ hóa từ Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-web-ui-synced-workspace-session.webp",[547,6949,6951],{"id":6950},"danh-sách-các-lệnh-khả-dụng-trên-buzz","Danh sách các lệnh khả dụng trên Buzz",[429,6953,6954],{},"Tất cả các lệnh mà các nền tảng khác hỗ trợ đều hoạt động mượt mà trên Buzz:",[6186,6956,6957,6967],{},[6189,6958,6959],{},[6192,6960,6961,6964],{},[6195,6962,6963],{},"Lệnh",[6195,6965,6966],{},"Chức năng",[6204,6968,6969,6979,6989,6999,7009,7019,7029,7039,7049,7068,7088],{},[6192,6970,6971,6976],{},[6209,6972,6973],{},[645,6974,6975],{},"\u002Fworkspace \u003Cfolder>",[6209,6977,6978],{},"Đăng ký một thư mục sẵn có làm workspace cho cuộc hội thoại (yêu cầu bật quyền trong cấu hình)",[6192,6980,6981,6986],{},[6209,6982,6983],{},[645,6984,6985],{},"\u002Fhelp",[6209,6987,6988],{},"Liệt kê tất cả các lệnh khả dụng",[6192,6990,6991,6996],{},[6209,6992,6993],{},[645,6994,6995],{},"\u002Ftime",[6209,6997,6998],{},"Hiển thị thời gian hiện tại của hệ thống",[6192,7000,7001,7006],{},[6209,7002,7003],{},[645,7004,7005],{},"\u002Fnew",[6209,7007,7008],{},"Khởi tạo một phiên trò chuyện hoàn toàn mới",[6192,7010,7011,7016],{},[6209,7012,7013],{},[645,7014,7015],{},"\u002Fclear",[6209,7017,7018],{},"Xóa trắng lịch sử trò chuyện hiện tại",[6192,7020,7021,7026],{},[6209,7022,7023],{},[645,7024,7025],{},"\u002Fstatus",[6209,7027,7028],{},"Kiểm tra trạng thái hoạt động của cầu nối",[6192,7030,7031,7036],{},[6209,7032,7033],{},[645,7034,7035],{},"\u002Fstats",[6209,7037,7038],{},"Xem số lượng đoạn chat và dòng trạng thái chi tiết của từng bridge (trên tất cả nền tảng, bao gồm cả Buzz)",[6192,7040,7041,7046],{},[6209,7042,7043],{},[645,7044,7045],{},"\u002Fcommands",[6209,7047,7048],{},"Xem bảng mô tả chi tiết của từng lệnh",[6192,7050,7051,7056],{},[6209,7052,7053],{},[645,7054,7055],{},"@path\u002Fto\u002Ffile",[6209,7057,7058,7059,1081,7061,3748,7064,7067],{},"Hoạt động hệt như tính năng mention tệp trên Web: mô hình đọc nội dung tệp tương đối theo workspace; gõ ",[645,7060,6420],{},[645,7062,7063],{},"@tiền_tố",[645,7065,7066],{},"\u002Ffiles \u003Ctiền_tố>"," để hiển thị danh sách tệp\u002Fthư mục phù hợp",[6192,7069,7070,7075],{},[6209,7071,7072],{},[645,7073,7074],{},"\u002Fmodel",[6209,7076,7077,7080,7081,7083,7084,7087],{},[645,7078,7079],{},"[provider model effort]"," — xác thực với danh mục LLM đang kích hoạt để đổi mô hình và mức suy luận; gõ ",[645,7082,7074],{}," để xem tùy chọn, ",[645,7085,7086],{},"\u002Fmodel reset"," để khôi phục mặc định",[6192,7089,7090,7095],{},[6209,7091,7092],{},[645,7093,7094],{},"\u002Feffort",[6209,7096,7097,7100,7101,7104],{},[645,7098,7099],{},"\u003Cid>"," chỉ điều chỉnh mức độ suy luận (reasoning effort); ",[645,7102,7103],{},"\u002Feffort reset"," khôi phục lại giá trị mặc định",[547,7106,7108],{"id":7107},"tóm-lược-về-bảo-mật","Tóm lược về bảo mật",[455,7110,7111,7124,7134],{},[458,7112,7113,7114,7116,7117,7119,7120,7123],{},"Khóa riêng ",[442,7115,6716],{}," chỉ nằm duy nhất trong ",[645,7118,6087],{}," (phân quyền tệp 0600, ghi nguyên tử) — không bao giờ bị lộ ra ngoài qua endpoint ",[645,7121,7122],{},"\u002Fgateway\u002Flist"," hay tệp nhật ký log.",[458,7125,7126,7127,3744,7130,7133],{},"Mọi sự kiện gửi đến đều được ",[442,7128,7129],{},"xác thực chữ ký mật mã",[645,7131,7132],{},"verifyEvent","), loại bỏ tin trùng lặp, lọc thông điệp tự phát và kiểm tra đề cập @mention trước khi chuyển tiếp tới tác nhân.",[458,7135,7136,3744,7139,7142],{},[442,7137,7138],{},"Việc đăng ký workspace được kiểm soát chặt bằng cấu hình",[645,7140,7141],{},"allowWorkspace: false"," theo mặc định) nhằm ngăn ngừa tình trạng các phiên gateway tự động phê duyệt quyền mở tệp ngoài ý muốn.",[447,7144,7146],{"id":7145},"lời-kết-cộng-tác-ai-phi-tập-trung-cùng-buzz","Lời kết: Cộng tác AI phi tập trung cùng Buzz",[429,7148,7149,7150,7152],{},"Khía cạnh phức tạp nhất khi tích hợp Buzz vào ",[645,7151,6046],{}," nằm ở việc đáp ứng chuẩn xác quy chuẩn giao thức Nostr. Nhờ nền tảng plugin sẵn có đã trừu tượng hóa rất tốt việc quản lý phiên và điều hướng lệnh, quá trình xây dựng cầu nối diễn ra vô cùng thuận lợi và ổn định ngay khi cơ chế xử lý sự kiện và truyền phát luồng chỉnh sửa tại chỗ được thiết lập.",[447,7154,4537],{"id":2612},[455,7156,7157,7165,7173],{},[458,7158,7159,7164],{},[569,7160,7163],{"href":7161,"rel":7162},"https:\u002F\u002Fgithub.com\u002Fa792883583\u002Fdsh-message-gateway\u002Fblob\u002Fmain\u002Fdocs\u002Farchitecture.md",[1654],"dsh-message-gateway architecture guide"," — tài liệu kiến trúc, hướng dẫn viết extension và lưu ý bảo mật",[458,7166,7167,7172],{},[569,7168,7171],{"href":7169,"rel":7170},"https:\u002F\u002Fgithub.com\u002Fnbd-wtf\u002Fnostr-tools",[1654],"nostr-tools"," — thư viện Nostr cốt lõi được sử dụng bên dưới",[458,7174,7175,7180],{},[569,7176,7179],{"href":7177,"rel":7178},"https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fdeer-flow\u002Fblob\u002Fmain\u002Fbackend\u002Fdocs\u002FIM_CHANNEL_CONNECTIONS.md",[1654],"deer-flow IM channel connections"," — mô hình tham khảo cho kết nối kênh nhắn tin tức thời",[2645,7182,7183],{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":424,"searchDepth":741,"depth":614,"links":7185},[7186,7187,7191,7198,7199],{"id":6065,"depth":741,"text":6066},{"id":6177,"depth":741,"text":6178,"children":7188},[7189,7190],{"id":6470,"depth":614,"text":6471},{"id":6498,"depth":614,"text":6499},{"id":6602,"depth":741,"text":6603,"children":7192},[7193,7194,7196,7197],{"id":6722,"depth":614,"text":6723},{"id":6857,"depth":614,"text":7195},"Cho phép mở quyền thư mục cục bộ với lệnh \u002Fworkspace",{"id":6950,"depth":614,"text":6951},{"id":7107,"depth":614,"text":7108},{"id":7145,"depth":741,"text":7146},{"id":2612,"depth":741,"text":4537},[2680,2679,2065,7201],"deepseek-harness","2026-09-30","Tích hợp DeepSeek Harness với Block Buzz bằng cầu nối Nostr. Thiết lập xác thực NIP-42, truyền phát tin nhắn chỉnh sửa tại chỗ và workspace đa tác nhân AI.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002FVI-Bringing-Buzz-to-DeepSeek-Harness.webp","Thẻ công nghệ 16:9 cao cấp với điểm nhấn màu chàm đậm và hổ phách minh họa cách kết nối DeepSeek Harness với Block Buzz thông qua cầu nối Nostr, có bảng glassmorphic sạch sẽ với kiểu chữ chính giữa.",{"schemaOrg":7207,"robots":2709,"sitemap":7229},[7208,7209],{"@type":2689,"headline":6028,"description":7203,"image":7204},{"@type":2691,"name":6028,"description":7203,"image":7204,"step":7210},[7211,7214,7217,7220,7223,7226],{"@type":2694,"name":7212,"text":7213},"Giai đoạn 1: Cài đặt plugin cổng kết nối","Cài đặt plugin dsh-message-gateway và khởi động dịch vụ dsh web.",{"@type":2694,"name":7215,"text":7216},"Giai đoạn 2: Truy cập cài đặt Message platforms","Mở giao diện Web DSH và điều hướng đến mục Message platforms.",{"@type":2694,"name":7218,"text":7219},"Giai đoạn 3: Định cấu hình cầu nối Buzz","Tạo cặp khóa Nostr, nhập Relay URL và danh sách kênh cần theo dõi.",{"@type":2694,"name":7221,"text":7222},"Giai đoạn 4: Đăng ký tác tử lên relay","Thêm trợ lý DSH vào Buzz Nostr relay bằng lệnh buzz-admin.",{"@type":2694,"name":7224,"text":7225},"Giai đoạn 5: Thêm tác tử vào kênh","Gán khóa HEX của tác tử vào các kênh cụ thể bằng buzz-cli.",{"@type":2694,"name":7227,"text":7228},"Giai đoạn 6: Kích hoạt liên kết workspace","Định cấu hình allowWorkspace trong cordis.patch.yml để cho phép lệnh thư mục cục bộ.",{"lastmod":7202},{"title":7231,"description":7203,"ogTitle":6028,"ogDescription":7203,"twitterTitle":6028,"twitterDescription":7203},"Plugin Buzz cho DeepSeek Harness: Tạo Cầu Nối Nostr","vi\u002Farticle\u002Fbringing-buzz-to-deepseek-harness",[6183,444,2716,7234,6046],"Tác tử AI","ZIProBuceyP_EtpE4Ozv_jHRd4oXizYxQLd5TQo7Fjg",{"id":2725,"title":2726,"author":2720,"body":2727,"category":4605,"date":4607,"description":4608,"extension":2683,"image":4609,"imageAlt":4610,"isPublished":772,"meta":4611,"minRead":1510,"navigation":772,"path":379,"seo":4618,"stem":4619,"tags":4620,"updatedAt":2711,"__hash__":4622},{"id":7238,"title":7239,"author":424,"body":7240,"category":7795,"date":7796,"description":7797,"extension":2683,"image":7798,"imageAlt":7799,"isPublished":772,"meta":7800,"minRead":827,"navigation":772,"path":367,"seo":7804,"stem":7806,"tags":7807,"updatedAt":2720,"__hash__":7811},"article\u002Fvi\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts.md","Cách kỹ năng Agent AI thay thế script khởi tạo ứng dụng Nuxt",{"type":426,"value":7241,"toc":7788},[7242,7256,7260,7263,7359,7362,7390,7396,7400,7415,7432,7436,7447,7608,7612,7694,7698,7706,7726,7733,7748,7759,7762,7768,7771,7777,7785],[429,7243,7244,7245,2559,7248,7251,7252,7255],{},"Khi bắt đầu một ứng dụng mới bằng framework Nuxt, chúng ta phải trải qua các bước tẻ nhạt như cài đặt các module và thiết lập các cấu hình như ",[645,7246,7247],{},"nuxt.config.ts",[645,7249,7250],{},"wrangler.jsonc",". Một đoạn script có thể giải quyết vấn đề này, nhưng nó sẽ chạm giới hạn khi các biến thể yêu cầu ngày càng tăng. Đây là lý do tại sao chúng tôi đã tìm hiểu và thay thế các script truyền thống bằng một ",[442,7253,7254],{},"kỹ năng của agent"," (agent skill).",[447,7257,7259],{"id":7258},"những-gì-mà-script-shell-truyền-thống-làm-tốt","Những gì mà Script Shell truyền thống làm tốt",[429,7261,7262],{},"Một script rất giỏi trong việc thực thi một tập hợp các hướng dẫn cố định theo trình tự với các quyết định được viết cứng (hardcode) trong mã nguồn.",[665,7264,7266],{"className":667,"code":7265,"language":669,"meta":424,"style":424},"#!\u002Fusr\u002Fbin\u002Fenv bash\nset -e\n\nnpx nuxi@latest init \"$1\" --template minimal --packageManager pnpm --no-gitInit -M @nuxt\u002Fui,@nuxthub\u002Fcore,@vueuse\u002Fnuxt\n\ncd \"$1\"\n\ncp ~\u002Ftemplates\u002Fnuxt.config.ts .\ncp ~\u002Ftemplates\u002Fwrangler.jsonc .\n",[645,7267,7268,7273,7280,7284,7323,7327,7337,7341,7350],{"__ignoreMap":424},[673,7269,7270],{"class":675,"line":676},[673,7271,7272],{"class":737},"#!\u002Fusr\u002Fbin\u002Fenv bash\n",[673,7274,7275,7278],{"class":675,"line":741},[673,7276,7277],{"class":785},"set",[673,7279,1627],{"class":687},[673,7281,7282],{"class":675,"line":614},[673,7283,773],{"emptyLinePlaceholder":772},[673,7285,7286,7288,7291,7294,7296,7300,7302,7305,7308,7311,7314,7317,7320],{"class":675,"line":776},[673,7287,4112],{"class":679},[673,7289,7290],{"class":687}," nuxi@latest",[673,7292,7293],{"class":687}," init",[673,7295,684],{"class":683},[673,7297,7299],{"class":7298},"sHdIc","$1",[673,7301,691],{"class":683},[673,7303,7304],{"class":687}," --template",[673,7306,7307],{"class":687}," minimal",[673,7309,7310],{"class":687}," --packageManager",[673,7312,7313],{"class":687}," pnpm",[673,7315,7316],{"class":687}," --no-gitInit",[673,7318,7319],{"class":687}," -M",[673,7321,7322],{"class":687}," @nuxt\u002Fui,@nuxthub\u002Fcore,@vueuse\u002Fnuxt\n",[673,7324,7325],{"class":675,"line":782},[673,7326,773],{"emptyLinePlaceholder":772},[673,7328,7329,7331,7333,7335],{"class":675,"line":827},[673,7330,996],{"class":785},[673,7332,684],{"class":683},[673,7334,7299],{"class":7298},[673,7336,702],{"class":683},[673,7338,7339],{"class":675,"line":832},[673,7340,773],{"emptyLinePlaceholder":772},[673,7342,7343,7345,7348],{"class":675,"line":838},[673,7344,1004],{"class":679},[673,7346,7347],{"class":687}," ~\u002Ftemplates\u002Fnuxt.config.ts",[673,7349,1312],{"class":687},[673,7351,7352,7354,7357],{"class":675,"line":850},[673,7353,1004],{"class":679},[673,7355,7356],{"class":687}," ~\u002Ftemplates\u002Fwrangler.jsonc",[673,7358,1312],{"class":687},[429,7360,7361],{},"Script này hoạt động tốt cho đến khi các vấn đề sau xảy ra:",[455,7363,7364,7370,7380],{},[458,7365,7366,7369],{},[442,7367,7368],{},"Các giá trị mặc định cố định."," Đoạn script hardcode module Nuxt UI; điều gì xảy ra nếu chúng ta muốn dùng module Ant Design UI? Mỗi tùy chọn module mới lại yêu cầu một đối số (argument) khác từ người dùng.",[458,7371,7372,7375,7376,7379],{},[442,7373,7374],{},"Không thể đọc được ý định của người dùng."," Yêu cầu \"Xây dựng cho tôi một trang blog\" cần ",[645,7377,7378],{},"@nuxt\u002Fcontent","; \"xây dựng cho tôi một trang web có bản tin (newsletter)\" cần Cloudflare D1 + Drizzle. Script không thể phân biệt được sự khác biệt này — mỗi biến thể lại cần một script mới.",[458,7381,7382,7385,7386,7389],{},[442,7383,7384],{},"Trở nên lỗi thời một cách lặng lẽ."," Các quy ước của Nuxt thay đổi giữa các phiên bản lớn. Nuxt 4 đã thay đổi thư mục nguồn thành ",[645,7387,7388],{},"app\u002F",". Một đoạn script được viết cho Nuxt 3 sẽ âm thầm khởi tạo (scaffold) sai cấu trúc thư mục mà không bao giờ cảnh báo cho người dùng.",[429,7391,7392,7395],{},[442,7393,7394],{},"Khởi tạo ứng dụng"," (app scaffolding) là một vấn đề về mặt quyết định chứ không phải thực thi. Đoạn script sẽ không thể mở rộng khi số lượng quyết định tăng lên.",[447,7397,7399],{"id":7398},"tại-sao-nên-sử-dụng-kỹ-năng-agent-ai-thay-vì-script-truyền-thống","Tại sao nên sử dụng Kỹ năng Agent AI thay vì Script truyền thống?",[429,7401,7402,7403,7406,7407,7410,7411,7414],{},"Kỹ năng của agent (agent skill) không phải là một tập hợp mã nguồn để thực thi, mà là một ",[442,7404,7405],{},"tập hợp kiến thức mà agent AI sẽ tuân theo",". Nó chứa tệp ",[645,7408,7409],{},"SKILL.md"," và có thể đóng gói bất kỳ tệp nào khác mà tác vụ yêu cầu (như tài liệu tham khảo, mẫu template và các script thực thi). Bài viết ",[569,7412,7413],{"href":351},"Kỹ năng của Agent AI: Chúng là gì và cách tạo lập chi tiết"," giải thích chi tiết cách thức hoạt động của một kỹ năng agent. Một kỹ năng giữ nguyên sự chuẩn xác của một đoạn script đồng thời bổ sung thêm các đánh giá hợp lý mà script còn thiếu:",[455,7416,7417,7420,7423,7426,7429],{},[458,7418,7419],{},"Suy luận ra ý định của người dùng để quyết định xem ứng dụng có cần cơ sở dữ liệu hay không.",[458,7421,7422],{},"Quyết định xem module tùy chọn nào là cần thiết từ danh sách được chỉ định. Ví dụ: Nuxt Content, i18n và công cụ phân tích là các tùy chọn bổ sung theo yêu cầu người dùng.",[458,7424,7425],{},"Thích ứng với hệ sinh thái hiện tại bằng cách sử dụng framework Nuxt mới nhất, NuxtHub cho các liên kết Cloudflare và Wrangler để triển khai (deploy).",[458,7427,7428],{},"Tự phục hồi khi một bước thực hiện bị thất bại.",[458,7430,7431],{},"Xác minh lại thông qua một danh sách kiểm tra (checklist) cuối cùng trước khi bàn giao dự án cho người dùng.",[447,7433,7435],{"id":7434},"đằng-sau-hậu-trường-của-kỹ-năng-scaffolding-nuxt-cloudflare-của-chúng-tôi","Đằng sau hậu trường của Kỹ năng Scaffolding Nuxt & Cloudflare của chúng tôi",[429,7437,7438,7439,7446],{},"Kỹ năng ",[569,7440,7443],{"href":7441,"rel":7442},"https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fscaffold-nuxt-cloudflare-app-skill",[1654],[645,7444,7445],{},"scaffold-nuxt-cloudflare-app-skill"," dẫn dắt qua một quy trình khởi tạo hướng tới môi trường sản xuất (production):",[591,7448,7449,7479,7499,7523,7553,7588,7594],{},[458,7450,7451,7454,7455],{},[442,7452,7453],{},"Làm rõ bất kỳ điều gì"," không thể tự động suy luận:\n",[455,7456,7457,7467,7470],{},[458,7458,7459,7460,3748,7463,7466],{},"UI kit (mặc định là ",[442,7461,7462],{},"Nuxt UI",[442,7464,7465],{},"Antdv Next",");",[458,7468,7469],{},"Có cần cơ sở dữ liệu hay không (chẳng hạn như Cloudflare D1);",[458,7471,7472,7473,3748,7476,7478],{},"Các module bổ sung như ",[645,7474,7475],{},"@nuxtjs\u002Fi18n",[645,7477,7378],{}," cho các tính năng CMS.",[458,7480,7481,7484,7485,7488,7489,7491,7492,7495,7496,599],{},[442,7482,7483],{},"Khởi tạo ứng dụng cơ bản"," bằng lệnh ",[645,7486,7487],{},"pnpm dlx nuxi@latest init"," để lấy phiên bản mới nhất của framework Nuxt với ",[645,7490,5505],{}," làm trình quản lý gói. Sau đó, nó thiết lập danh sách cho phép build gốc (native-build allowlists) để môi trường build của Cloudflare có thể biên dịch ",[645,7493,7494],{},"better-sqlite3","\u002F",[645,7497,7498],{},"sharp",[458,7500,7501,1077,7504,3748,7507,1081,7510,1081,7513,1081,7516,1081,7519,7522],{},[442,7502,7503],{},"Cài đặt các module từ bảng quyết định",[645,7505,7506],{},"@nuxt\u002Fui",[645,7508,7509],{},"@antdv-next\u002Fnuxt",[645,7511,7512],{},"@nuxt\u002Fimage",[645,7514,7515],{},"@nuxtjs\u002Fseo",[645,7517,7518],{},"@nuxthub\u002Fcore",[645,7520,7521],{},"@vueuse\u002Fnuxt",", cộng với Drizzle\u002FD1, Nuxt Content và i18n chỉ khi được chọn.",[458,7524,7525,1261,7528],{},[442,7526,7527],{},"Bố trí cấu trúc thư mục",[455,7529,7530,7535,7540,7545,7550],{},[458,7531,7532,7534],{},[645,7533,7388],{}," (chuẩn Nuxt 4)",[458,7536,7537],{},[645,7538,7539],{},"server\u002F",[458,7541,7542],{},[645,7543,7544],{},"shared\u002F",[458,7546,7547],{},[645,7548,7549],{},"tests\u002F",[458,7551,7552],{},"các tệp cấu hình ở thư mục gốc.",[458,7554,7555,1261,7560],{},[442,7556,7557,7558],{},"Cấu hình ",[645,7559,7247],{},[455,7561,7562,7571,7578,7583],{},[458,7563,7564,7495,7567,7570],{},[645,7565,7566],{},"site.url",[645,7568,7569],{},"site.name"," cho SEO",[458,7572,7573,7574,7577],{},"Khối ",[645,7575,7576],{},"hub"," của NuxtHub cho Cloudflare",[458,7579,7580],{},[645,7581,7582],{},"routeRules",[458,7584,7585],{},[645,7586,7587],{},"compatibilityDate",[458,7589,7590],{},[442,7591,7557,7592],{},[645,7593,7250],{},[458,7595,7596,7599,7600,7603,7604,7607],{},[442,7597,7598],{},"Thiết lập Vitest và ESLint",", sau đó chạy ",[442,7601,7602],{},"checklist cuối cùng"," bao gồm ",[645,7605,7606],{},"pnpm install && pnpm dev"," trước khi hoàn thành công việc.",[447,7609,7611],{"id":7610},"script-shell-vs-kỹ-năng-agent-ai-so-sánh-trực-tiếp","Script Shell vs Kỹ năng Agent AI: So sánh trực tiếp",[6186,7613,7614,7626],{},[6189,7615,7616],{},[6192,7617,7618,7620,7623],{},[6195,7619],{},[6195,7621,7622],{},"Script",[6195,7624,7625],{},"Kỹ năng",[6204,7627,7628,7639,7650,7661,7672,7683],{},[6192,7629,7630,7633,7636],{},[6209,7631,7632],{},"Ý định của người dùng",[6209,7634,7635],{},"❌ giá trị mặc định cố định",[6209,7637,7638],{},"✅ thích ứng theo yêu cầu",[6192,7640,7641,7644,7647],{},[6209,7642,7643],{},"Ra quyết định",[6209,7645,7646],{},"chỉ khi lập trình sẵn flag",[6209,7648,7649],{},"✅ đánh giá tại thời điểm chạy",[6192,7651,7652,7655,7658],{},[6209,7653,7654],{},"Thay đổi phiên bản",[6209,7656,7657],{},"viết lại thủ công",[6209,7659,7660],{},"✅ kiểm tra trạng thái hiện tại",[6192,7662,7663,7666,7669],{},[6209,7664,7665],{},"Khắc phục lỗi",[6209,7667,7668],{},"dừng hoạt động",[6209,7670,7671],{},"✅ sửa lỗi và tiếp tục",[6192,7673,7674,7677,7680],{},[6209,7675,7676],{},"Xác minh kết quả",[6209,7678,7679],{},"❌",[6209,7681,7682],{},"✅ checklist cuối cùng",[6192,7684,7685,7688,7691],{},[6209,7686,7687],{},"Chi phí bảo trì",[6209,7689,7690],{},"phình to flag, cập nhật phiên bản",[6209,7692,7693],{},"chỉnh sửa Markdown, không sửa code",[447,7695,7697],{"id":7696},"cách-cài-đặt-kỹ-năng-agent-ai-bằng-cli-npx-skills","Cách cài đặt Kỹ năng Agent AI bằng CLI npx skills",[429,7699,7700,7701,1276],{},"Cài đặt cực kỳ đơn giản chỉ với một lệnh duy nhất bằng ",[569,7702,7705],{"href":7703,"rel":7704},"https:\u002F\u002Fgithub.com\u002Fvercel-labs\u002Fskills",[1654],"skills CLI",[665,7707,7709],{"className":667,"code":7708,"language":669,"meta":424,"style":424},"npx skills add https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fscaffold-nuxt-cloudflare-app-skill.git -g\n",[645,7710,7711],{"__ignoreMap":424},[673,7712,7713,7715,7718,7720,7723],{"class":675,"line":676},[673,7714,4112],{"class":679},[673,7716,7717],{"class":687}," skills",[673,7719,6630],{"class":687},[673,7721,7722],{"class":687}," https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fscaffold-nuxt-cloudflare-app-skill.git",[673,7724,7725],{"class":687}," -g\n",[429,7727,7728,7729],{},"CLI sẽ clone repo, tìm kỹ năng và hỏi xem nên áp dụng cho agent nào trong số 77 agent được hỗ trợ:\n",[435,7730],{"alt":7731,"src":7732},"Giao diện dòng lệnh hiển thị quá trình cài đặt kỹ năng scaffolding Nuxt bằng câu lệnh CLI npx skills add","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20AI%20Agent%20Skills%20Replace%20Nuxt%20App%20Scaffolding%20Scripts\u002Fnpx-skills-add-scaffold-nuxt-installation.webp",[429,7734,7735,7736,7739,7740,7743,7744],{},"Chúng tôi chọn ",[442,7737,7738],{},"Symlink"," (phương pháp được đề xuất), phương pháp này cài đặt kỹ năng một lần duy nhất vào thư mục ",[645,7741,7742],{},"~\u002F.agents\u002Fskills"," và liên kết tất cả các agent được chọn tới bản sao duy nhất này.\n",[435,7745],{"alt":7746,"src":7747},"Màn hình terminal hiển thị tóm tắt cài đặt và thiết lập symlink cho các kỹ năng agent tập trung","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20AI%20Agent%20Skills%20Replace%20Nuxt%20App%20Scaffolding%20Scripts\u002Fnpx-skills-installation-summary-details.webp",[455,7749,7750],{},[458,7751,7752],{},[6487,7753,7754,7755,7758],{},"Vui lòng tham khảo bài viết này, ",[569,7756,7757],{"href":359},"Giải quyết sự phân mảnh kỹ năng của Agent AI với npx skills",", để biết cách tập trung hóa các kỹ năng của agent vào một nguồn sự thật duy nhất (source of truth).",[429,7760,7761],{},"Mở Claude Code sẽ xác nhận kỹ năng đã được cài đặt thành công.",[429,7763,7764],{},[435,7765],{"alt":7766,"src":7767},"Giao diện dòng lệnh Claude Code hiển thị lệnh gạch chéo scaffold-nuxt mới được cài đặt, đang hoạt động và sẵn sàng sử dụng","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20AI%20Agent%20Skills%20Replace%20Nuxt%20App%20Scaffolding%20Scripts\u002Fclaude-code-scaffold-nuxt-slash-command-active.webp",[429,7769,7770],{},"Từ đó, một câu lệnh bằng ngôn ngữ tự nhiên là tất cả những gì bạn cần:",[7772,7773,7774],"blockquote",{},[429,7775,7776],{},"\"Scaffold a new Nuxt app deployed to Cloudflare Workers — Nuxt UI, a blog section, and a D1 database\"",[429,7778,7779,7780,7784],{},"Kỹ năng này hoàn toàn là mã nguồn mở; hãy truy cập ",[569,7781,7783],{"href":7441,"rel":7782},[1654],"repo GitHub"," và trải nghiệm thử nhé.",[2645,7786,7787],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":424,"searchDepth":741,"depth":614,"links":7789},[7790,7791,7792,7793,7794],{"id":7258,"depth":741,"text":7259},{"id":7398,"depth":741,"text":7399},{"id":7434,"depth":741,"text":7435},{"id":7610,"depth":741,"text":7611},{"id":7696,"depth":741,"text":7697},[2680],"2026-08-25","Khởi tạo Nuxt trên Cloudflare Workers dễ dàng. Tìm hiểu lý do tại sao chúng tôi thay thế shell script bằng kỹ năng Agent AI và cách cài đặt qua npx skills.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20AI%20Agent%20Skills%20Replace%20Nuxt%20App%20Scaffolding%20Scripts\u002FVI-How-AI-Agent-Skills-Replace-Nuxt-App-Scaffolding-Scripts.webp","Khởi tạo Nuxt trên Cloudflare: Shell Script vs Kỹ năng AI - So sánh script shell truyền thống với kỹ năng Agent AI thông minh.",{"schemaOrg":7801,"robots":2709,"sitemap":7803},[7802],{"@type":2689,"headline":7239,"description":7797,"image":7798},{"lastmod":7796},{"title":7805,"description":7797,"ogTitle":7239,"ogDescription":7797,"twitterTitle":7239,"twitterDescription":7797},"Khởi tạo Nuxt trên Cloudflare: Shell Script vs Kỹ năng AI","vi\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts",[7808,2719,7809,7810],"Nuxt","AI Agent","Scaffolding","iLBYG2BUUfqE4EYnr7uB_-yd-WlwdGymPwL0-YvZNsI",1792489999520]