[{"data":1,"prerenderedAt":14115},["ShallowReactive",2],{"published-article-paths":3,"search-navigation":348,"category-articles-en-deepseek-harness":421},[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",[422,1675,2615,4057,6219,8101,8669,9442,9970,10359,10979,11434,11643,11864,12199,12892,13322,13568],{"id":423,"title":354,"author":424,"body":425,"category":1630,"date":1634,"description":1635,"extension":1636,"image":1637,"imageAlt":1638,"isPublished":1059,"meta":1639,"minRead":1667,"navigation":1059,"path":39,"seo":1668,"stem":356,"tags":1670,"updatedAt":1673,"__hash__":1674},"article\u002Fen\u002Farticle\u002Fbringing-buzz-to-deepseek-harness.md","",{"type":426,"value":427,"toc":1614},"minimark",[428,436,461,469,472,477,483,528,531,591,595,602,866,869,873,878,885,889,903,907,918,971,978,982,985,1016,1020,1025,1076,1081,1087,1092,1098,1113,1126,1130,1139,1170,1192,1240,1248,1254,1260,1267,1273,1278,1285,1299,1305,1314,1354,1357,1363,1370,1376,1380,1383,1533,1537,1570,1574,1580,1584,1610],[429,430,431],"p",{},[432,433],"img",{"alt":434,"src":435},"DeepSeek Harness message gateway connected to Block Buzz channel overview","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-nostr-gateway-overview.webp",[429,437,438,439,449,450,455,456,460],{},"The DeepSeek Harness (DSH) plugin, ",[440,441,442],"strong",{},[443,444,448],"a",{"href":445,"rel":446},"https:\u002F\u002Fgithub.com\u002Fa792883583\u002Fdsh-message-gateway",[447],"nofollow","dsh-message-gateway",", extends the DeepSeek Harness assistant across messaging platforms such as Discord, Telegram, and WeChat. The plugin repository was forked and extended to add the ",[440,451,452],{},[443,453,454],{"href":383},"Buzz"," platform to the list. The forked repository is available on GitHub at ",[443,457,458],{"href":458,"rel":459},"https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fdsh-message-gateway",[447],".",[462,463],"article-card",{"description":464,"image":465,"image-alt":466,"label":467,"min-read":468,"title":382,"to":383},"Learn how to self-host Block's Buzz on a Linux VPS behind Cloudflare DNS. Run a secure, Nostr-powered workspace where humans and AI agents collaborate.","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","A premium 16:9 technology card with deep blue and orange accents illustrating how to self-host Block's Buzz relay on an Ubuntu VPS, featuring a clean glassmorphic panel with centered typography.","Prerequisite guide","12",[429,470,471],{},"The DSH assistant joins a Buzz relay as a member, receives direct messages (DMs) and channel messages where it is @mentioned, and responds through the same per-chat agent pipeline used by the Web UI.",[473,474,476],"h2",{"id":475},"architecture-of-the-dsh-message-gateway-plugin","Architecture of the dsh-message-gateway Plugin",[429,478,479,480,482],{},"The architecture of the ",[440,481,448],{}," plugin splits into two parts:",[484,485,486,518],"ul",{},[487,488,489,492,493,497,498,501,502,505,506,509,510,513,514,517],"li",{},[440,490,491],{},"Host"," (Node): ",[494,495,496],"code",{},"gateway-store"," (credentials, ",[494,499,500],{},"~\u002F.dsh\u002Fgateway.json","), ",[494,503,504],{},"platforms.ts"," (platform definitions + connection tests), ",[494,507,508],{},"routes.ts"," (",[494,511,512],{},"\u002Fgateway\u002F*"," endpoints), and ",[494,515,516],{},"bridge-manager.ts"," (the resident bridges: per-chat independent agent sessions + streamed replies).",[487,519,520,523,524,527],{},[440,521,522],{},"Client"," (browser): the sidebar \"",[440,525,526],{},"Message platforms","\" page where you save credentials, test connections, and monitor status.",[429,529,530],{},"Adding a new platform involves the following steps:",[532,533,534,551,565],"ol",{},[487,535,536,539,540,543,544,547,548,460],{},[440,537,538],{},"A bridge class"," — ",[494,541,542],{},"start\u002Fstop\u002Fstatus"," plus an ",[494,545,546],{},"onText(text, frame)"," callback, mirroring ",[494,549,550],{},"wecom-bridge.ts",[487,552,553,556,557,560,561,564],{},[440,554,555],{},"Bridge-manager wiring"," — reuse the existing per-chat pipeline (",[494,558,559],{},"ensureAgentForKey"," + ",[494,562,563],{},"pendingMap",") and swap in the platform's reply sink.",[487,566,567,570,571,574,575,578,579,582,583,586,587,590],{},[440,568,569],{},"Storage\u002Froute wiring"," — in ",[494,572,573],{},"\u002Fgateway\u002Fsave"," and ",[494,576,577],{},"\u002Fgateway\u002Fdelete",": ",[440,580,581],{},"saving credentials starts the bridge, deleting stops it"," — plus an ",[494,584,585],{},"autoStartXxx"," flag so ",[494,588,589],{},"dsh web"," reconnects on boot.",[473,592,594],{"id":593},"building-the-buzz-bridge-nostr-protocol-event-lifecycle","Building the Buzz Bridge: Nostr Protocol & Event Lifecycle",[429,596,597,598,601],{},"The ",[440,599,600],{},"DeepSeek Harness"," was used to implement the Buzz bridge. The implementation conforms to the following Nostr protocol specifications:",[603,604,605,631],"table",{},[606,607,608],"thead",{},[609,610,611,617],"tr",{},[612,613,614],"th",{},[440,615,616],{},"Transport",[612,618,619,620,623,624,627,628],{},"One NIP-42-authenticated WebSocket; default ",[494,621,622],{},"ws:\u002F\u002Flocalhost:3000","; ",[494,625,626],{},"http(s):\u002F\u002F"," is normalised to ",[494,629,630],{},"ws(s):\u002F\u002F",[632,633,634,653,681,699,723,747,769,783,796,812,829,843],"tbody",{},[609,635,636,642],{},[637,638,639],"td",{},[440,640,641],{},"Auth",[637,643,644,645,648,649,652],{},"AUTH event ",[494,646,647],{},"kind 22242",", tags ",[494,650,651],{},"[[\"relay\", url], [\"challenge\", challenge]]",", empty content, signed with the agent key",[609,654,655,660],{},[637,656,657],{},[440,658,659],{},"Subscriptions",[637,661,662,578,665,668,669,672,673,676,677,680],{},[440,663,664],{},"Channel-scoped",[494,666,667],{},"REQ {\"kinds\":[9], \"#h\":[\u003Cuuid>]}"," — one REQ per channel. A global ",[494,670,671],{},"kinds:[9]"," REQ gets EOSE but never fans out; multi-value ",[494,674,675],{},"#h"," does ",[440,678,679],{},"not"," work",[609,682,683,688],{},[637,684,685],{},[440,686,687],{},"Discovery",[637,689,690,691,694,695,698],{},"Historical ",[494,692,693],{},"REQ {kinds:[39000]}"," for channel metadata (",[494,696,697],{},"type == \"dm\""," marks a DM channel)",[609,700,701,706],{},[637,702,703],{},[440,704,705],{},"Membership",[637,707,708,709,712,713,715,716,719,720],{},"Live ",[494,710,711],{},"REQ {kinds:[44100,44101], \"#p\":[our pubkey], since: now-60s}"," — 44100 = added, 44101 = removed, each carrying ",[494,714,429],{},"+",[494,717,718],{},"h","; membership changes update subscriptions ",[440,721,722],{},"without reconnect",[609,724,725,730],{},[637,726,727],{},[440,728,729],{},"Chat events",[637,731,732,735,736,739,740,743,744],{},[494,733,734],{},"kind 9"," with tags ",[494,737,738],{},"[\"h\", channel]",", optional ",[494,741,742],{},"[\"e\", replyTo]",", ",[494,745,746],{},"[\"p\", mention]",[609,748,749,754],{},[637,750,751],{},[440,752,753],{},"In-place edits",[637,755,756,759,760,560,762,765,766,768],{},[494,757,758],{},"kind 40003"," with ",[494,761,718],{},[494,763,764],{},"e","→target; content replaces; 64 KB relay cap → keep payloads ≤ 60,000 B; oversized replies chunk — chunk 0 rides the edit, overflow chunks are appended as threaded kind-9 messages (",[494,767,764],{},"→thread root)",[609,770,771,776],{},[637,772,773],{},[440,774,775],{},"CLOSED frames",[637,777,778,779,782],{},"Pre-AUTH ",[494,780,781],{},"auth-required"," is normal bootstrap (finish AUTH, reopen subs); post-AUTH → bounded resubscribe (3 attempts, 0\u002F1\u002F2 s backoff); reconnect rebuilds everything",[609,784,785,790],{},[637,786,787],{},[440,788,789],{},"Relay caps",[637,791,792,793],{},"≤ 2000 historical events per subscription, newest-first even with ",[494,794,795],{},"since",[609,797,798,803],{},[637,799,800],{},[440,801,802],{},"Mention gating",[637,804,805,806,808,809,811],{},"Act on inbound kind-9 only when (a) ",[494,807,429],{},"-tag includes our pubkey, (b) channel is a DM, or (c) the ",[494,810,764],{}," root is our own event (thread follow). Ignore our own pubkey — loop prevention",[609,813,814,819],{},[637,815,816],{},[440,817,818],{},"Outbound mentions",[637,820,821,822,825,826,828],{},"Outbound text is published verbatim — the relay does not pre-check ",[494,823,824],{},"@"," tokens; ",[494,827,429],{}," tags carry the inbound author + up to 7 other mentioned pubkeys (max 8)",[609,830,831,836],{},[637,832,833],{},[440,834,835],{},"DMs",[637,837,838,839,842],{},"Relay-scoped plaintext channels (",[494,840,841],{},"type: \"dm\""," metadata) — no NIP-04\u002F44 encryption in this bridge",[609,844,845,850],{},[637,846,847],{},[440,848,849],{},"Attachments (inbound)",[637,851,852,853,509,856,743,859,743,862,865],{},"NIP-92 ",[494,854,855],{},"imeta",[494,857,858],{},"url",[494,860,861],{},"sha256",[494,863,864],{},"m",") → plain http(s) download, verify SHA-256, 20 MB cap, max 4 per message; outbound images have no documented publish path → explicitly unsupported",[429,867,868],{},"The diagram below illustrates how the Buzz bridge bootstraps:",[432,870],{"src":871,"alt":872},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-bootstrap.webp","Sequence diagram illustrating the Buzz bridge bootstrap and NIP-42 authentication process",[874,875,877],"h3",{"id":876},"real-time-streaming-via-nostr-in-place-edits-kind-40003","Real-Time Streaming via Nostr In-Place Edits (Kind 40003)",[429,879,880,881,884],{},"Nostr has no native typing indicator, and events are append-only. To make replies feel responsive and alive, the Buzz bridge ",[440,882,883],{},"simulates streaming using in-place edits"," as shown below:",[432,886],{"src":887,"alt":888},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-reply.webp","Diagram of in-place editing flow simulating live streaming responses with kind 40003 events",[484,890,891],{},[487,892,893],{},[894,895,896,897,899,900,902],"em",{},"The Buzz bridge publishes a placeholder ",[494,898,734],{}," event, then progressively rewrites it with rate-limited ",[494,901,758],{}," in-place edits, before writing the final edit when the agent completes its run. This mirrors the \"send then edit\" pattern used by Telegram and Discord bridges.",[874,904,906],{"id":905},"bridging-deepseek-harness-workspaces-via-chat-commands","Bridging DeepSeek Harness Workspaces via Chat Commands",[429,908,909,910,913,914,917],{},"The DSH \"Workspaces\" feature in the Web UI is backed by the ",[494,911,912],{},"workspaceRegistry"," service (",[494,915,916],{},"@deepseek-ai\u002Fdsh-workspace","):",[919,920,924],"pre",{"className":921,"code":922,"language":923,"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",[494,925,926],{"__ignoreMap":424},[927,928,931,935,939,943,947,950,952,954,956,960,963,965,968],"span",{"class":929,"line":930},"line",1,[927,932,934],{"class":933},"spNyl","const",[927,936,938],{"class":937},"sTEyZ"," existing ",[927,940,942],{"class":941},"sMK4o","=",[927,944,946],{"class":945},"s7zQu"," await",[927,948,949],{"class":937}," ctx",[927,951,460],{"class":941},[927,953,912],{"class":937},[927,955,460],{"class":941},[927,957,959],{"class":958},"s2Zo4","resolveByPath",[927,961,962],{"class":937},"(request",[927,964,460],{"class":941},[927,966,967],{"class":937},"path)",[927,969,970],{"class":941},";\n",[429,972,973,974,977],{},"The Buzz bridge exposes a chat command, ",[494,975,976],{},"\u002Fworkspace \u003Cfolder>",", which registers an existing folder in DSH. Any new session through the gateway attaches to it and appears in the Web UI.",[432,979],{"src":980,"alt":981},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-workspace.webp","Architecture of DeepSeek Harness workspace registration from chat commands via gateway",[429,983,984],{},"Three design considerations to note:",[484,986,987,997,1006],{},[487,988,989,992,993,996],{},[440,990,991],{},"Switching folder = new session."," ",[494,994,995],{},"cwd"," is written into the session header at creation and cannot be mutated afterwards.",[487,998,999,992,1002,1005],{},[440,1000,1001],{},"Folder must already exist.",[494,1003,1004],{},"create"," rejects non-existent paths.",[487,1007,1008,1011,1012,1015],{},[440,1009,1010],{},"Security-sensitive command."," Every session operates under an ",[440,1013,1014],{},"auto-approve"," policy, granting file access to the target folder.",[473,1017,1019],{"id":1018},"step-by-step-installation-configuration-guide","Step-by-Step Installation & Configuration Guide",[532,1021,1022],{},[487,1023,1024],{},"Run the following commands:",[919,1026,1030],{"className":1027,"code":1028,"language":1029,"meta":424,"style":424},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","dsh plugin --profile web add https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fdsh-message-gateway.git\n\n# Start DSH web\ndsh web\n","bash",[494,1031,1032,1054,1061,1068],{"__ignoreMap":424},[927,1033,1034,1038,1042,1045,1048,1051],{"class":929,"line":930},[927,1035,1037],{"class":1036},"sBMFI","dsh",[927,1039,1041],{"class":1040},"sfazB"," plugin",[927,1043,1044],{"class":1040}," --profile",[927,1046,1047],{"class":1040}," web",[927,1049,1050],{"class":1040}," add",[927,1052,1053],{"class":1040}," https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fdsh-message-gateway.git\n",[927,1055,1057],{"class":929,"line":1056},2,[927,1058,1060],{"emptyLinePlaceholder":1059},true,"\n",[927,1062,1064],{"class":929,"line":1063},3,[927,1065,1067],{"class":1066},"sHwdD","# Start DSH web\n",[927,1069,1071,1073],{"class":929,"line":1070},4,[927,1072,1037],{"class":1036},[927,1074,1075],{"class":1040}," web\n",[532,1077,1078],{"start":1056},[487,1079,1080],{},"Once the DSH Web UI is opened in a web browser, click on the 'Message platforms' icon:",[429,1082,1083],{},[432,1084],{"alt":1085,"src":1086},"DeepSeek Harness Web UI sidebar highlighting the Message platforms configuration menu","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-web-ui-message-platforms-sidebar-icon.webp",[532,1088,1089],{"start":1063},[487,1090,1091],{},"Click on 'Buzz' on the left panel:",[429,1093,1094],{},[432,1095],{"alt":1096,"src":1097},"Buzz bridge configuration settings panel in DeepSeek Harness message gateway","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-message-gateway-buzz-config-panel.webp",[532,1099,1100,1107,1110],{"start":1070},[487,1101,1102,1103,1106],{},"Click 'Generate keypair' to generate a Nostr key pair. Copy the ",[494,1104,1105],{},"npub"," public key somewhere safe, as you will need it later.",[487,1108,1109],{},"Enter the 'Relay URL' and 'Channels' (the allowlist of channel UUIDs to subscribe to).",[487,1111,1112],{},"Click the 'Save' button.",[429,1114,1115,1116,1119,1120,1123,1124,460],{},"Saving the form stores the credentials and ",[440,1117,1118],{},"starts the bridge",". The ",[494,1121,1122],{},"nsec"," private key is treated as a secret and stored exclusively in ",[494,1125,500],{},[874,1127,1129],{"id":1128},"registering-the-dsh-assistant-keypair-on-the-buzz-nostr-relay","Registering the DSH Assistant Keypair on the Buzz Nostr Relay",[429,1131,1132,1135,1136,1138],{},[440,1133,1134],{},"Add the DSH assistant to the relay as a member."," The pubkey will be the ",[494,1137,1105],{}," generated above:",[919,1140,1142],{"className":1027,"code":1141,"language":1029,"meta":424,"style":424},"docker compose exec relay buzz-admin add-member --pubkey npub123123123\n",[494,1143,1144],{"__ignoreMap":424},[927,1145,1146,1149,1152,1155,1158,1161,1164,1167],{"class":929,"line":930},[927,1147,1148],{"class":1036},"docker",[927,1150,1151],{"class":1040}," compose",[927,1153,1154],{"class":1040}," exec",[927,1156,1157],{"class":1040}," relay",[927,1159,1160],{"class":1040}," buzz-admin",[927,1162,1163],{"class":1040}," add-member",[927,1165,1166],{"class":1040}," --pubkey",[927,1168,1169],{"class":1040}," npub123123123\n",[429,1171,1172,1175,1176,1179,1180,1183,1184,1187,1188,1191],{},[440,1173,1174],{},"Add the DSH assistant to a channel."," Adding a member registers it on the relay, but the member will not yet appear or be searchable within channels. To add the agent to a specific channel using ",[494,1177,1178],{},"buzz-cli",", note that the ",[494,1181,1182],{},"--pubkey"," parameter must be in ",[440,1185,1186],{},"HEX"," format, not npub (the ",[494,1189,1190],{},"buzz-admin add-member"," command prints the member's HEX pubkey).",[919,1193,1195],{"className":1027,"code":1194,"language":1029,"meta":424,"style":424},"buzz channels add-member --channel \u003CCHANNEL_UUID> --pubkey \u003CAGENT_HEX> --role member\n",[494,1196,1197],{"__ignoreMap":424},[927,1198,1199,1202,1205,1207,1210,1213,1216,1219,1222,1224,1226,1229,1232,1234,1237],{"class":929,"line":930},[927,1200,1201],{"class":1036},"buzz",[927,1203,1204],{"class":1040}," channels",[927,1206,1163],{"class":1040},[927,1208,1209],{"class":1040}," --channel",[927,1211,1212],{"class":941}," \u003C",[927,1214,1215],{"class":1040},"CHANNEL_UUI",[927,1217,1218],{"class":937},"D",[927,1220,1221],{"class":941},">",[927,1223,1166],{"class":1040},[927,1225,1212],{"class":941},[927,1227,1228],{"class":1040},"AGENT_HE",[927,1230,1231],{"class":937},"X",[927,1233,1221],{"class":941},[927,1235,1236],{"class":1040}," --role",[927,1238,1239],{"class":1040}," member\n",[462,1241],{"description":1242,"image":465,"image-alt":1243,"label":1244,"min-read":1245,"title":1246,"to":1247},"Step-by-step instructions to install and configure buzz-cli for managing Nostr channels, member keys, and AI agent permissions.","Configuring buzz-cli commands to manage Nostr channel members and agent roles","CLI guide","5","How to Install and Use buzz-cli","\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues#install-buzz-cli",[429,1249,1250,1251,1253],{},"Update the DSH assistant's profile on the Nostr relay to a more meaningful display name using ",[494,1252,1178],{},":",[429,1255,1256],{},[432,1257],{"alt":1258,"src":1259},"Updating the DeepSeek Harness assistant display name on Nostr relay using buzz-cli","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-assistant-buzz-cli-profile-update.webp",[429,1261,1262,1263,1266],{},"Send a ",[440,1264,1265],{},"Wave"," (Buzz's DM greeting) to the DSH assistant. The wave comes back:",[429,1268,1269],{},[432,1270],{"alt":1271,"src":1272},"Testing connection by sending a Wave DM to DeepSeek Harness assistant in Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-dm-wave-greeting-reply.webp",[429,1274,1275],{},[894,1276,1277],{},"Sending a Wave as a DM to the DSH assistant — the bridge is alive.",[874,1279,1281,1282],{"id":1280},"enabling-workspace","Enabling ",[494,1283,1284],{},"\u002Fworkspace",[429,1286,1287,1288,1291,1292,1295,1296,1298],{},"Because the ",[494,1289,1290],{},"allowWorkspace"," setting defaults to ",[494,1293,1294],{},"false",", issuing the ",[494,1297,1284],{}," command is initially rejected:",[429,1300,1301],{},[432,1302],{"alt":1303,"src":1304},"Error notification showing workspace command rejected when allowWorkspace is disabled","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-workspace-command-rejected-error.webp",[429,1306,1307,1308,1311,1312,1253],{},"Enable it in ",[494,1309,1310],{},"~\u002F.dsh\u002Fprofiles\u002Fweb\u002Fcordis.patch.yml",", then restart ",[494,1313,589],{},[919,1315,1319],{"className":1316,"code":1317,"language":1318,"meta":424,"style":424},"language-yml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","- id: ui-message-gateway\n  config:\n    allowWorkspace: true\n","yml",[494,1320,1321,1335,1343],{"__ignoreMap":424},[927,1322,1323,1326,1330,1332],{"class":929,"line":930},[927,1324,1325],{"class":941},"-",[927,1327,1329],{"class":1328},"swJcz"," id",[927,1331,1253],{"class":941},[927,1333,1334],{"class":1040}," ui-message-gateway\n",[927,1336,1337,1340],{"class":929,"line":1056},[927,1338,1339],{"class":1328},"  config",[927,1341,1342],{"class":941},":\n",[927,1344,1345,1348,1350],{"class":929,"line":1063},[927,1346,1347],{"class":1328},"    allowWorkspace",[927,1349,1253],{"class":941},[927,1351,1353],{"class":1352},"sfNiH"," true\n",[429,1355,1356],{},"After the restart:",[429,1358,1359],{},[432,1360],{"alt":1361,"src":1362},"Successful confirmation message after executing workspace registration command in Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-buzz-workspace-command-success-confirmation.webp",[429,1364,1365,1366,1369],{},"One gotcha: this assumes the workspace folder (",[494,1367,1368],{},"TechVoyage"," in the screenshots) lives in the default user directory. Specify a full path otherwise. Any new session registered under this workspace via Buzz also appears in the DeepSeek Harness Web UI.",[429,1371,1372],{},[432,1373],{"alt":1374,"src":1375},"DeepSeek Harness Web UI displaying the active workspace session synchronized from Buzz","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002Fdsh-web-ui-synced-workspace-session.webp",[874,1377,1379],{"id":1378},"available-commands","Available Commands",[429,1381,1382],{},"Everything that other supported platforms offer works seamlessly on Buzz:",[603,1384,1385,1395],{},[606,1386,1387],{},[609,1388,1389,1392],{},[612,1390,1391],{},"Command",[612,1393,1394],{},"What it does",[632,1396,1397,1406,1416,1426,1436,1446,1456,1466,1476,1496,1516],{},[609,1398,1399,1403],{},[637,1400,1401],{},[494,1402,976],{},[637,1404,1405],{},"Register an existing folder as the chat's workspace (config-gated)",[609,1407,1408,1413],{},[637,1409,1410],{},[494,1411,1412],{},"\u002Fhelp",[637,1414,1415],{},"List available commands",[609,1417,1418,1423],{},[637,1419,1420],{},[494,1421,1422],{},"\u002Ftime",[637,1424,1425],{},"Current time",[609,1427,1428,1433],{},[637,1429,1430],{},[494,1431,1432],{},"\u002Fnew",[637,1434,1435],{},"Start a fresh session",[609,1437,1438,1443],{},[637,1439,1440],{},[494,1441,1442],{},"\u002Fclear",[637,1444,1445],{},"Clear the conversation",[609,1447,1448,1453],{},[637,1449,1450],{},[494,1451,1452],{},"\u002Fstatus",[637,1454,1455],{},"Bridge status",[609,1457,1458,1463],{},[637,1459,1460],{},[494,1461,1462],{},"\u002Fstats",[637,1464,1465],{},"Chat count + per-bridge status lines (all platforms, incl. Buzz)",[609,1467,1468,1473],{},[637,1469,1470],{},[494,1471,1472],{},"\u002Fcommands",[637,1474,1475],{},"Every command descriptor",[609,1477,1478,1483],{},[637,1479,1480],{},[494,1481,1482],{},"@path\u002Fto\u002Ffile",[637,1484,1485,1486,743,1488,1491,1492,1495],{},"Works exactly like Web @ mentions — the model reads the file relative to the chat's workspace; a bare ",[494,1487,824],{},[494,1489,1490],{},"@prefix",", or ",[494,1493,1494],{},"\u002Ffiles \u003Cprefix>"," replies with matching files\u002Ffolders from the same discovery source",[609,1497,1498,1503],{},[637,1499,1500],{},[494,1501,1502],{},"\u002Fmodel",[637,1504,1505,1508,1509,1511,1512,1515],{},[494,1506,1507],{},"[provider model effort]"," — validated against the live LLM catalog, switches that chat's model + effort; ",[494,1510,1502],{}," alone lists options, ",[494,1513,1514],{},"\u002Fmodel reset"," restores defaults",[609,1517,1518,1523],{},[637,1519,1520],{},[494,1521,1522],{},"\u002Feffort",[637,1524,1525,1528,1529,1532],{},[494,1526,1527],{},"\u003Cid>"," adjusts reasoning effort only; ",[494,1530,1531],{},"\u002Feffort reset"," restores the default",[874,1534,1536],{"id":1535},"security-in-snapshot","Security in Snapshot",[484,1538,1539,1551,1561],{},[487,1540,597,1541,1543,1544,1546,1547,1550],{},[440,1542,1122],{}," lives only in ",[494,1545,500],{}," (0600, atomic write) — never in ",[494,1548,1549],{},"\u002Fgateway\u002Flist",", never in logs.",[487,1552,1553,1554,509,1557,1560],{},"Every inbound event is ",[440,1555,1556],{},"signature-verified",[494,1558,1559],{},"verifyEvent","), deduplicated, self-filtered, and mention-gated before it reaches the agent.",[487,1562,1563,509,1566,1569],{},[440,1564,1565],{},"Workspace registration is config-gated",[494,1567,1568],{},"allowWorkspace: false"," by default) since gateway sessions auto-approve.",[473,1571,1573],{"id":1572},"key-takeaways","Key Takeaways",[429,1575,1576,1577,1579],{},"The harder part of adding Buzz to ",[494,1578,448],{}," was fulfilling the Nostr protocol contract. The existing plugin already provided a architectural foundation for per-chat sessions and command routing, making the bridge integration straightforward.",[473,1581,1583],{"id":1582},"references","References:",[484,1585,1586,1594,1602],{},[487,1587,1588,1593],{},[443,1589,1592],{"href":1590,"rel":1591},"https:\u002F\u002Fgithub.com\u002Fa792883583\u002Fdsh-message-gateway\u002Fblob\u002Fmain\u002Fdocs\u002Farchitecture.md",[447],"dsh-message-gateway architecture guide"," — extension recipe, module map, security notes (bridges default to hidden)",[487,1595,1596,1601],{},[443,1597,1600],{"href":1598,"rel":1599},"https:\u002F\u002Fgithub.com\u002Fnbd-wtf\u002Fnostr-tools",[447],"nostr-tools"," — the Nostr library used under the hood",[487,1603,1604,1609],{},[443,1605,1608],{"href":1606,"rel":1607},"https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fdeer-flow\u002Fblob\u002Fmain\u002Fbackend\u002Fdocs\u002FIM_CHANNEL_CONNECTIONS.md",[447],"deer-flow IM channel connections"," — reference for IM channel connection patterns",[1611,1612,1613],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}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 .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 .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 pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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}",{"title":424,"searchDepth":1056,"depth":1063,"links":1615},[1616,1617,1621,1628,1629],{"id":475,"depth":1056,"text":476},{"id":593,"depth":1056,"text":594,"children":1618},[1619,1620],{"id":876,"depth":1063,"text":877},{"id":905,"depth":1063,"text":906},{"id":1018,"depth":1056,"text":1019,"children":1622},[1623,1624,1626,1627],{"id":1128,"depth":1063,"text":1129},{"id":1280,"depth":1063,"text":1625},"Enabling \u002Fworkspace",{"id":1378,"depth":1063,"text":1379},{"id":1535,"depth":1063,"text":1536},{"id":1572,"depth":1056,"text":1573},{"id":1582,"depth":1056,"text":1583},[1631,1632,1201,1633],"ai-agents","collaboration","deepseek-harness","2026-09-30","Integrate DeepSeek Harness with Block Buzz using a Nostr bridge. Configure NIP-42 auth, in-place message streaming, and per-channel agent workspaces.","md","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FBringing%20Buzz%20to%20DeepSeek%20Harness\u002FEN-Bringing-Buzz-to-DeepSeek-Harness.webp","A premium 16:9 technology card with deep indigo and amber accents illustrating how to connect DeepSeek Harness to Block Buzz via a Nostr gateway, featuring a clean glassmorphic panel with centered typography.",{"schemaOrg":1640,"robots":1665,"sitemap":1666},[1641,1643],{"@type":1642,"headline":354,"description":1635,"image":1637},"TechArticle",{"@type":1644,"name":354,"description":1635,"image":1637,"step":1645},"HowTo",[1646,1650,1653,1656,1659,1662],{"@type":1647,"name":1648,"text":1649},"HowToStep","Phase 1: Install Gateway Plugin","Install the dsh-message-gateway plugin and start the DSH web service.",{"@type":1647,"name":1651,"text":1652},"Phase 2: Access Message Platforms","Open the DSH Web UI and navigate to Message platforms settings.",{"@type":1647,"name":1654,"text":1655},"Phase 3: Configure Buzz Bridge","Generate a Nostr keypair, enter the Relay URL, and set channel subscriptions.",{"@type":1647,"name":1657,"text":1658},"Phase 4: Register Agent on Relay","Add the DSH assistant to the Buzz Nostr relay using buzz-admin.",{"@type":1647,"name":1660,"text":1661},"Phase 5: Assign Agent to Channel","Add the assistant HEX pubkey to designated channels using buzz-cli.",{"@type":1647,"name":1663,"text":1664},"Phase 6: Enable Workspace Access","Configure allowWorkspace in cordis.patch.yml to enable local folder commands.","index, follow",{"lastmod":1634},9,{"title":1669,"description":1635,"ogTitle":354,"ogDescription":1635,"twitterTitle":354,"twitterDescription":1635},"DeepSeek Harness Buzz Plugin: Build a Nostr Bridge",[600,454,1671,1672,448],"Nostr","AI Agents",null,"3ILGY8-EUYBkB7RoFM4yH49qiefLt3OYDlH5S748n_g",{"id":1676,"title":362,"author":424,"body":1677,"category":2568,"date":2570,"description":2571,"extension":1636,"image":2572,"imageAlt":2573,"isPublished":1059,"meta":2574,"minRead":2238,"navigation":1059,"path":43,"seo":2608,"stem":364,"tags":2610,"updatedAt":2607,"__hash__":2614},"article\u002Fen\u002Farticle\u002Fexposing-hermes-agent-to-private-network-using-cloudflare-warp.md",{"type":426,"value":1678,"toc":2550},[1679,1693,1702,1706,1709,1721,1725,1733,1737,1741,1790,1794,1931,1935,1968,1972,1975,2041,2044,2080,2083,2110,2114,2124,2129,2168,2256,2260,2265,2282,2291,2371,2376,2422,2426,2471,2485,2489,2533,2537,2547],[429,1680,1681,1682,1685,1686,759,1689,1692],{},"A common challenge arises when you want to access your ",[440,1683,1684],{},"Hermes Agent"," from other devices such as laptops, tablets, or phones without exposing it to the public internet. Utilizing ",[440,1687,1688],{},"Cloudflare WARP",[440,1690,1691],{},"Cloudflare Zero Trust"," allows you to expose the Hermes Agent globally without opening a single inbound port on your firewall.",[429,1694,1695,1696,1698,1699,1701],{},"If you followed our previous guide, '",[443,1697,374],{"href":375},"', a Hermes Agent is already up and running 24\u002F7. Instead of dealing with the overhead of traditional VPNs, we will use the ",[440,1700,1688],{}," client to expose the Hermes Agent to a private network over the internet.",[473,1703,1705],{"id":1704},"understanding-the-architecture","Understanding the Architecture",[429,1707,1708],{},"The components at play:",[532,1710,1711,1716],{},[487,1712,1713,1715],{},[440,1714,1691],{},": The dashboard at Cloudflare where you define routing rules and access policies.",[487,1717,1718,1720],{},[440,1719,1688],{},": The client application installed on your devices (VPS, laptops, phones). It intercepts traffic destined for your private network and routes it securely.",[874,1722,1724],{"id":1723},"prerequisites","Prerequisites",[484,1726,1727,1730],{},[487,1728,1729],{},"A running Hermes Agent on your VPS.",[487,1731,1732],{},"A free Cloudflare account.",[473,1734,1736],{"id":1735},"step-by-step-guide","Step-by-Step Guide",[874,1738,1740],{"id":1739},"step-1-set-up-cloudflare-zero-trust","Step 1: Set Up Cloudflare Zero Trust",[532,1742,1743,1751,1758,1769,1776,1783],{},[487,1744,1745,1746,460],{},"Log in to your ",[443,1747,1750],{"href":1748,"rel":1749},"https:\u002F\u002Fdash.cloudflare.com\u002F",[447],"Cloudflare Dashboard",[487,1752,1753,1754],{},"Click on 'Zero Trust' from the left menu.\n",[432,1755],{"alt":1756,"src":1757},"Cloudflare dashboard left sidebar navigation menu with Zero Trust option","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-zero-trust-left-menu.webp",[487,1759,1760,1761,1764,1765],{},"If this is your first time, you will be prompted to choose a plan (the Free tier is perfectly fine for this setup) and name your team (e.g., ",[494,1762,1763],{},"ai-team",").\n",[432,1766],{"alt":1767,"src":1768},"Setting up first-time Cloudflare Zero Trust account and naming the team","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-zero-trust-team-setup.webp",[487,1770,1771,1772],{},"Click on 'Access' then 'Policies' to create an access policy defining who has access to the network.\n",[432,1773],{"alt":1774,"src":1775},"Cloudflare Zero Trust Access Policies page showing newly configured access rules","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-access-policies-page.webp",[487,1777,1778,1779],{},"Click on 'Create new policy'.\n",[432,1780],{"alt":1781,"src":1782},"Cloudflare Access policies page showing no policies added and a button to create a new policy.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-no-policies-create-button.png",[487,1784,1785,1786],{},"Select 'Emails' and enter your email under 'Policy rules'.\n",[432,1787],{"alt":1788,"src":1789},"Cloudflare Access policy rule configuration screen with an email address specified as the inclusion criteria.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-policy-rule-email.png",[874,1791,1793],{"id":1792},"step-2-set-up-cloudflare-warp-client-on-vps","Step 2: Set Up Cloudflare WARP Client on VPS",[532,1795,1796,1806,1812,1819,1822,1837,1840,1924],{},[487,1797,1798,1799,574,1802,1805],{},"Run ",[494,1800,1801],{},"sudo apt update",[494,1803,1804],{},"sudo apt install cloudflare-warp"," in the terminal on your VPS.",[487,1807,1798,1808,1811],{},[494,1809,1810],{},"warp-cli registration new \u003CTEAM-NAME>"," in the terminal on your VPS, which will print out a URL.",[487,1813,1814,1815,1818],{},"Copy the printed URL, which will look like ",[494,1816,1817],{},"https:\u002F\u002F\u003Cteam>.cloudflareaccess.com\u002Fwarp",", and paste it in your browser for authentication.",[487,1820,1821],{},"Since email authentication is used in the policy rule setup above, enter your email to authenticate.",[487,1823,1824,1825,1828,1829,1832,1833,1836],{},"On the '",[440,1826,1827],{},"Success","' page in the browser, right-click and select '",[440,1830,1831],{},"Inspect","' on the blue '",[440,1834,1835],{},"Open Cloudflare WARP","' button.",[487,1838,1839],{},"Copy the long token that is shown in the button's link.",[487,1841,1798,1842,1845,1846,1849,1850],{},[494,1843,1844],{},"warp-cli --accept-tos registration token \"https:\u002F\u002F\u003Cteam>.cloudflareaccess.com\u002Fauth?token=\u003Ccopied_token>\""," in the terminal on your VPS to connect it to Cloudflare Zero Trust.",[1847,1848],"br",{},"If the 'Error: Failed to communicate with the WARP API' is encounter on Ubuntu 26, run the following commands:",[919,1851,1853],{"className":1027,"code":1852,"language":1029,"meta":424,"style":424},"sudo systemctl restart warp-svc.service\n\n# Check status\nsudo systemctl status warp-svc.service\n\n# Run the warp-cli registration token again\nwarp-cli --accept-tos registration token   \"https:\u002F\u002F\u003Cteam>.cloudflareaccess.com\u002Fauth?token=\u003Ccopied_token>\"\n",[494,1854,1855,1869,1873,1878,1889,1894,1900],{"__ignoreMap":424},[927,1856,1857,1860,1863,1866],{"class":929,"line":930},[927,1858,1859],{"class":1036},"sudo",[927,1861,1862],{"class":1040}," systemctl",[927,1864,1865],{"class":1040}," restart",[927,1867,1868],{"class":1040}," warp-svc.service\n",[927,1870,1871],{"class":929,"line":1056},[927,1872,1060],{"emptyLinePlaceholder":1059},[927,1874,1875],{"class":929,"line":1063},[927,1876,1877],{"class":1066},"# Check status\n",[927,1879,1880,1882,1884,1887],{"class":929,"line":1070},[927,1881,1859],{"class":1036},[927,1883,1862],{"class":1040},[927,1885,1886],{"class":1040}," status",[927,1888,1868],{"class":1040},[927,1890,1892],{"class":929,"line":1891},5,[927,1893,1060],{"emptyLinePlaceholder":1059},[927,1895,1897],{"class":929,"line":1896},6,[927,1898,1899],{"class":1066},"# Run the warp-cli registration token again\n",[927,1901,1903,1906,1909,1912,1915,1918,1921],{"class":929,"line":1902},7,[927,1904,1905],{"class":1036},"warp-cli",[927,1907,1908],{"class":1040}," --accept-tos",[927,1910,1911],{"class":1040}," registration",[927,1913,1914],{"class":1040}," token",[927,1916,1917],{"class":941},"   \"",[927,1919,1920],{"class":1040},"https:\u002F\u002F\u003Cteam>.cloudflareaccess.com\u002Fauth?token=\u003Ccopied_token>",[927,1922,1923],{"class":941},"\"\n",[487,1925,1926,1927],{},"Head back to the Cloudflare Zero Trust dashboard, and click on 'Devices'. Your VPS device should now be displayed.\n",[432,1928],{"alt":1929,"src":1930},"Zero Trust Devices dashboard confirming the Linux VPS is connected","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-zero-trust-devices-vps-connected.webp",[874,1932,1934],{"id":1933},"step-3-set-up-traffic-routing","Step 3: Set Up Traffic Routing",[532,1936,1937,1944,1951,1958],{},[487,1938,1939,1940],{},"Click the profile for your VPS on the Devices dashboard.\n",[432,1941],{"alt":1942,"src":1943},"Accessing details and split tunnel settings for the registered VPS device","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-zero-trust-device-profile.webp",[487,1945,1946,1947],{},"Scroll down to the 'Split Tunnels' section.\n",[432,1948],{"alt":1949,"src":1950},"Split Tunnels section under VPS profile settings","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-zero-trust-split-tunnels-section.webp",[487,1952,1953,1954],{},"Click the 'Manage' button and configure the settings as shown below. Replace the IP address if necessary.\n",[432,1955],{"alt":1956,"src":1957},"Managing Split Tunnels IP and hostname exclusions in Cloudflare settings","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-zero-trust-manage-split-tunnels.webp",[487,1959,1960,1961,574,1964,1967],{},"Exposing the ",[494,1962,1963],{},"address",[494,1965,1966],{},"host"," will route traffic to your services over the same private network.",[874,1969,1971],{"id":1970},"step-4-configure-firewall-on-the-vps","Step 4: Configure Firewall on the VPS",[429,1973,1974],{},"Enable the firewall to allow the '100.96.0.0\u002F12' subnet only, blocking all other public incoming access.",[919,1976,1978],{"className":1027,"code":1977,"language":1029,"meta":424,"style":424},"sudo ufw enable \nsudo ufw default allow outgoing \nsudo ufw default deny incoming\nsudo ufw allow in from 100.96.0.0\u002F12\n",[494,1979,1980,1993,2010,2024],{"__ignoreMap":424},[927,1981,1982,1984,1987,1990],{"class":929,"line":930},[927,1983,1859],{"class":1036},[927,1985,1986],{"class":1040}," ufw",[927,1988,1989],{"class":1040}," enable",[927,1991,1992],{"class":937}," \n",[927,1994,1995,1997,1999,2002,2005,2008],{"class":929,"line":1056},[927,1996,1859],{"class":1036},[927,1998,1986],{"class":1040},[927,2000,2001],{"class":1040}," default",[927,2003,2004],{"class":1040}," allow",[927,2006,2007],{"class":1040}," outgoing",[927,2009,1992],{"class":937},[927,2011,2012,2014,2016,2018,2021],{"class":929,"line":1063},[927,2013,1859],{"class":1036},[927,2015,1986],{"class":1040},[927,2017,2001],{"class":1040},[927,2019,2020],{"class":1040}," deny",[927,2022,2023],{"class":1040}," incoming\n",[927,2025,2026,2028,2030,2032,2035,2038],{"class":929,"line":1070},[927,2027,1859],{"class":1036},[927,2029,1986],{"class":1040},[927,2031,2004],{"class":1040},[927,2033,2034],{"class":1040}," in",[927,2036,2037],{"class":1040}," from",[927,2039,2040],{"class":1040}," 100.96.0.0\u002F12\n",[429,2042,2043],{},"Allow loopback traffic to avoid breaking local services:",[919,2045,2047],{"className":1027,"code":2046,"language":1029,"meta":424,"style":424},"sudo ufw allow in on lo\nsudo ufw allow out on lo\n",[494,2048,2049,2065],{"__ignoreMap":424},[927,2050,2051,2053,2055,2057,2059,2062],{"class":929,"line":930},[927,2052,1859],{"class":1036},[927,2054,1986],{"class":1040},[927,2056,2004],{"class":1040},[927,2058,2034],{"class":1040},[927,2060,2061],{"class":1040}," on",[927,2063,2064],{"class":1040}," lo\n",[927,2066,2067,2069,2071,2073,2076,2078],{"class":929,"line":1056},[927,2068,1859],{"class":1036},[927,2070,1986],{"class":1040},[927,2072,2004],{"class":1040},[927,2074,2075],{"class":1040}," out",[927,2077,2061],{"class":1040},[927,2079,2064],{"class":1040},[429,2081,2082],{},"Reload the firewall and verify status:",[919,2084,2086],{"className":1027,"code":2085,"language":1029,"meta":424,"style":424},"sudo ufw reload \nsudo ufw status verbose\n",[494,2087,2088,2099],{"__ignoreMap":424},[927,2089,2090,2092,2094,2097],{"class":929,"line":930},[927,2091,1859],{"class":1036},[927,2093,1986],{"class":1040},[927,2095,2096],{"class":1040}," reload",[927,2098,1992],{"class":937},[927,2100,2101,2103,2105,2107],{"class":929,"line":1056},[927,2102,1859],{"class":1036},[927,2104,1986],{"class":1040},[927,2106,1886],{"class":1040},[927,2108,2109],{"class":1040}," verbose\n",[874,2111,2113],{"id":2112},"step-5-expose-hermes-agent-to-the-private-network","Step 5: Expose Hermes Agent to the Private Network",[429,2115,2116,2117,2120,2121,460],{},"We will expose the ",[440,2118,2119],{},"Hermes Agent Web Dashboard"," to our private network and use the default authentication provider, ",[440,2122,2123],{},"Nous Research",[2125,2126,2128],"h4",{"id":2127},"set-up-the-auth-provider","Set Up the Auth Provider",[532,2130,2131,2140,2147,2154,2161],{},[487,2132,2133,2134,2139],{},"Head to ",[443,2135,2138],{"href":2136,"rel":2137},"https:\u002F\u002Fportal.nousresearch.com",[447],"portal.nousresearch.com"," to register an account.",[487,2141,2142,2143],{},"Select 'Local Dashboards'.\n",[432,2144],{"alt":2145,"src":2146},"Selecting Local Dashboards option in the Nous Research portal","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fnous-portal-local-dashboards-selection.webp",[487,2148,2149,2150],{},"Click 'Register Dashboard'.\n",[432,2151],{"alt":2152,"src":2153},"Clicking Register Dashboard button to create a new dashboard entry","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fnous-portal-register-dashboard.webp",[487,2155,2156,2157],{},"Enter the private network IP address of your VPS as the 'Dashboard redirect URI' and click 'Save'.\n",[432,2158],{"alt":2159,"src":2160},"Registering the private network VPS IP address as redirect URI in Nous Research portal","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fnous-portal-register-redirect-uri.webp",[487,2162,2163,2164,2167],{},"Copy the 'OAuth client ID' and paste it in your ",[494,2165,2166],{},"config.yaml"," file:",[919,2169,2173],{"className":2170,"code":2171,"language":2172,"meta":424,"style":424},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","dashboard:\n  theme: default\n  show_token_analytics: false\n  oauth:\n    client_id: agent:cmq02x7ha0002jk0ba3kfnb\n    portal_url: https:\u002F\u002Fportal.nousresearch.com\n  basic_auth:\n    username: ''\n    password_hash: ''\n","yaml",[494,2174,2175,2182,2192,2202,2209,2219,2229,2236,2247],{"__ignoreMap":424},[927,2176,2177,2180],{"class":929,"line":930},[927,2178,2179],{"class":1328},"dashboard",[927,2181,1342],{"class":941},[927,2183,2184,2187,2189],{"class":929,"line":1056},[927,2185,2186],{"class":1328},"  theme",[927,2188,1253],{"class":941},[927,2190,2191],{"class":1040}," default\n",[927,2193,2194,2197,2199],{"class":929,"line":1063},[927,2195,2196],{"class":1328},"  show_token_analytics",[927,2198,1253],{"class":941},[927,2200,2201],{"class":1352}," false\n",[927,2203,2204,2207],{"class":929,"line":1070},[927,2205,2206],{"class":1328},"  oauth",[927,2208,1342],{"class":941},[927,2210,2211,2214,2216],{"class":929,"line":1891},[927,2212,2213],{"class":1328},"    client_id",[927,2215,1253],{"class":941},[927,2217,2218],{"class":1040}," agent:cmq02x7ha0002jk0ba3kfnb\n",[927,2220,2221,2224,2226],{"class":929,"line":1896},[927,2222,2223],{"class":1328},"    portal_url",[927,2225,1253],{"class":941},[927,2227,2228],{"class":1040}," https:\u002F\u002Fportal.nousresearch.com\n",[927,2230,2231,2234],{"class":929,"line":1902},[927,2232,2233],{"class":1328},"  basic_auth",[927,2235,1342],{"class":941},[927,2237,2239,2242,2244],{"class":929,"line":2238},8,[927,2240,2241],{"class":1328},"    username",[927,2243,1253],{"class":941},[927,2245,2246],{"class":941}," ''\n",[927,2248,2249,2252,2254],{"class":929,"line":1667},[927,2250,2251],{"class":1328},"    password_hash",[927,2253,1253],{"class":941},[927,2255,2246],{"class":941},[2125,2257,2259],{"id":2258},"set-up-systemd-to-autostart-the-hermes-dashboard","Set Up Systemd to Autostart the Hermes Dashboard",[532,2261,2262],{},[487,2263,2264],{},"Create a service file:",[919,2266,2270],{"className":2267,"code":2268,"language":2269,"meta":424,"style":424},"language-shell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","sudo nano \u002Fetc\u002Fsystemd\u002Fsystem\u002Fhermes-dashboard.service\n","shell",[494,2271,2272],{"__ignoreMap":424},[927,2273,2274,2276,2279],{"class":929,"line":930},[927,2275,1859],{"class":1036},[927,2277,2278],{"class":1040}," nano",[927,2280,2281],{"class":1040}," \u002Fetc\u002Fsystemd\u002Fsystem\u002Fhermes-dashboard.service\n",[532,2283,2284],{"start":1056},[487,2285,2286,2287,2290],{},"Paste the following configuration, ensuring ",[494,2288,2289],{},"--host 0.0.0.0"," is part of the command:",[919,2292,2296],{"className":2293,"code":2294,"language":2295,"meta":424,"style":424},"language-ini shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[Unit]\nDescription=Hermes Dashboard\nAfter=network.target\n\n[Service]\nUser=hermes\nWorkingDirectory=\u002Fhome\u002Fhermes\nExecStart=\u002Fhome\u002Fhermes\u002F.local\u002Fbin\u002Fhermes dashboard --host 0.0.0.0\nRestart=always\nRestartSec=10\nEnvironment=PATH=\u002Fhome\u002Fhermes\u002F.local\u002Fbin:\u002Fusr\u002Flocal\u002Fbin:\u002Fusr\u002Fbin:\u002Fbin\n\n[Install]\nWantedBy=multi-user.target\n","ini",[494,2297,2298,2303,2308,2313,2317,2322,2327,2332,2337,2342,2348,2354,2359,2365],{"__ignoreMap":424},[927,2299,2300],{"class":929,"line":930},[927,2301,2302],{},"[Unit]\n",[927,2304,2305],{"class":929,"line":1056},[927,2306,2307],{},"Description=Hermes Dashboard\n",[927,2309,2310],{"class":929,"line":1063},[927,2311,2312],{},"After=network.target\n",[927,2314,2315],{"class":929,"line":1070},[927,2316,1060],{"emptyLinePlaceholder":1059},[927,2318,2319],{"class":929,"line":1891},[927,2320,2321],{},"[Service]\n",[927,2323,2324],{"class":929,"line":1896},[927,2325,2326],{},"User=hermes\n",[927,2328,2329],{"class":929,"line":1902},[927,2330,2331],{},"WorkingDirectory=\u002Fhome\u002Fhermes\n",[927,2333,2334],{"class":929,"line":2238},[927,2335,2336],{},"ExecStart=\u002Fhome\u002Fhermes\u002F.local\u002Fbin\u002Fhermes dashboard --host 0.0.0.0\n",[927,2338,2339],{"class":929,"line":1667},[927,2340,2341],{},"Restart=always\n",[927,2343,2345],{"class":929,"line":2344},10,[927,2346,2347],{},"RestartSec=10\n",[927,2349,2351],{"class":929,"line":2350},11,[927,2352,2353],{},"Environment=PATH=\u002Fhome\u002Fhermes\u002F.local\u002Fbin:\u002Fusr\u002Flocal\u002Fbin:\u002Fusr\u002Fbin:\u002Fbin\n",[927,2355,2357],{"class":929,"line":2356},12,[927,2358,1060],{"emptyLinePlaceholder":1059},[927,2360,2362],{"class":929,"line":2361},13,[927,2363,2364],{},"[Install]\n",[927,2366,2368],{"class":929,"line":2367},14,[927,2369,2370],{},"WantedBy=multi-user.target\n",[532,2372,2373],{"start":1063},[487,2374,2375],{},"Enable and start the service:",[919,2377,2379],{"className":2267,"code":2378,"language":2269,"meta":424,"style":424},"sudo systemctl daemon-reload\nsudo systemctl enable hermes-dashboard\nsudo systemctl start hermes-dashboard\nsudo systemctl status hermes-dashboard\n",[494,2380,2381,2390,2401,2412],{"__ignoreMap":424},[927,2382,2383,2385,2387],{"class":929,"line":930},[927,2384,1859],{"class":1036},[927,2386,1862],{"class":1040},[927,2388,2389],{"class":1040}," daemon-reload\n",[927,2391,2392,2394,2396,2398],{"class":929,"line":1056},[927,2393,1859],{"class":1036},[927,2395,1862],{"class":1040},[927,2397,1989],{"class":1040},[927,2399,2400],{"class":1040}," hermes-dashboard\n",[927,2402,2403,2405,2407,2410],{"class":929,"line":1063},[927,2404,1859],{"class":1036},[927,2406,1862],{"class":1040},[927,2408,2409],{"class":1040}," start",[927,2411,2400],{"class":1040},[927,2413,2414,2416,2418,2420],{"class":929,"line":1070},[927,2415,1859],{"class":1036},[927,2417,1862],{"class":1040},[927,2419,1886],{"class":1040},[927,2421,2400],{"class":1040},[874,2423,2425],{"id":2424},"step-6-install-cloudflare-warp-client-on-desktop","Step 6: Install Cloudflare WARP Client on Desktop",[532,2427,2428,2436,2439,2446,2453,2460],{},[487,2429,2430,2431,460],{},"Download the Cloudflare WARP client from ",[443,2432,2435],{"href":2433,"rel":2434},"https:\u002F\u002Fdevelopers.cloudflare.com\u002Fwarp-client\u002Fget-started\u002F",[447],"Cloudflare's portal",[487,2437,2438],{},"Open and launch the Cloudflare WARP client after installation.",[487,2440,2441,2442],{},"Log in when prompted.\n",[432,2443],{"alt":2444,"src":2445},"Cloudflare WARP client login prompt on desktop machine","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-warp-desktop-login-prompt.webp",[487,2447,2448,2449],{},"A 'Success' page will be displayed after a successful login.\n",[432,2450],{"alt":2451,"src":2452},"Authentication success webpage after logging in to Cloudflare Zero Trust on desktop","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-warp-desktop-login-success.webp",[487,2454,2455,2456],{},"The WARP client should now show it is connected to your Zero Trust team.\n",[432,2457],{"alt":2458,"src":2459},"Desktop Cloudflare WARP client confirming active connection to Zero Trust private network","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-warp-desktop-client-connected.webp",[487,2461,2462,2463,2466,2467],{},"Navigate to your web browser and enter your private IP (e.g., ",[494,2464,2465],{},"100.96.0.3","). The Hermes Web Dashboard should load successfully.\n",[432,2468],{"alt":2469,"src":2470},"Accessing the private Hermes Agent Web Dashboard in browser on desktop","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fhermes-agent-dashboard-desktop-view.webp",[2472,2473,2474],"blockquote",{},[429,2475,2476,2479,2480,2484],{},[440,2477,2478],{},"Pro Tip for macOS Users:"," If you are using the WARP client to access multiple Cloudflare accounts, check out our quick guide on ",[440,2481,2482],{},[443,2483,398],{"href":399}," to make switching between accounts seamless.",[874,2486,2488],{"id":2487},"step-7-install-cloudflare-warp-client-on-ios-devices","Step 7: Install Cloudflare WARP Client on iOS Devices",[532,2490,2491,2498,2506,2514,2522],{},[487,2492,2493,2494,2497],{},"Install ",[440,2495,2496],{},"Cloudflare One"," from the App Store.",[487,2499,2500,2501],{},"Open the Cloudflare One app and enter your team name when prompted.\n",[432,2502],{"alt":2503,"src":2504,"width":2505},"Entering Cloudflare Zero Trust team name in Cloudflare One app on iOS","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-one-ios-team-name-prompt.webp",239,[487,2507,2508,2509],{},"Log in using the same email address that was configured in the policy rule above.\n",[432,2510],{"alt":2511,"src":2512,"width":2513},"Email authentication prompt for Cloudflare Zero Trust on iOS","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-one-ios-email-login.webp",229,[487,2515,2516,2517],{},"Once it is connected, it should look like the following:\n",[432,2518],{"alt":2519,"src":2520,"width":2521},"Cloudflare One app showing connected status on iOS mobile device","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fcloudflare-one-ios-client-connected.webp",322,[487,2523,2524,2525,2527,2528],{},"Navigate to your web browser and enter the private IP ",[494,2526,2465],{}," to access the Hermes Web Dashboard on your mobile device.\n",[432,2529],{"alt":2530,"src":2531,"width":2532},"Accessing Hermes Agent Web Dashboard interface on mobile phone browser","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FExposing%20Hermes%20Agent%20to%20Private%20Network%20Using%20Cloudflare%20WARP\u002Fhermes-agent-dashboard-mobile-view.webp",345,[473,2534,2536],{"id":2535},"conclusion","Conclusion",[429,2538,2539,2540,2542,2543,2546],{},"With ",[440,2541,1691],{}," handling identity policies and the ",[440,2544,2545],{},"WARP"," client routing traffic over an encrypted tunnel, your Hermes Agent is securely reachable from your devices globally. This setup lays a secure, robust foundation for building and accessing a fully remote, private AI infrastructure.",[1611,2548,2549],{},"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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}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":1056,"depth":1063,"links":2551},[2552,2555,2567],{"id":1704,"depth":1056,"text":1705,"children":2553},[2554],{"id":1723,"depth":1063,"text":1724},{"id":1735,"depth":1056,"text":1736,"children":2556},[2557,2558,2559,2560,2561,2565,2566],{"id":1739,"depth":1063,"text":1740},{"id":1792,"depth":1063,"text":1793},{"id":1933,"depth":1063,"text":1934},{"id":1970,"depth":1063,"text":1971},{"id":2112,"depth":1063,"text":2113,"children":2562},[2563,2564],{"id":2127,"depth":1070,"text":2128},{"id":2258,"depth":1070,"text":2259},{"id":2424,"depth":1063,"text":2425},{"id":2487,"depth":1063,"text":2488},{"id":2535,"depth":1056,"text":2536},[1631,2569],"security","2026-07-09","Learn how to securely expose and access your Hermes Agent globally using Cloudflare WARP and Zero Trust without opening inbound firewall ports.","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","Securely exposing Hermes Agent to a private network using Cloudflare Zero Trust and WARP tunnel",{"schemaOrg":2575,"robots":1665,"sitemap":2606},[2576],{"@type":1644,"headline":362,"description":2571,"name":362,"image":2572,"step":2577},[2578,2582,2586,2590,2594,2598,2602],{"@type":1647,"name":2579,"text":2580,"url":2581,"image":1757},"Set Up Cloudflare Zero Trust","Log in to your Cloudflare Dashboard. Click on 'Zero Trust' from the left menu. If this is your first time, you will be prompted to choose a plan (the Free tier is perfectly fine for this setup) and name your team (e.g., ai-team). Click on 'Access' th","#step-1",{"@type":1647,"name":2583,"text":2584,"url":2585,"image":1930},"Set Up Cloudflare WARP Client on VPS","Run sudo apt update and sudo apt install cloudflare-warp in the terminal on your VPS. Run warp-cli registration new \u003CTEAM-NAME> in the terminal on your VPS, which will print out a URL. Copy the printed URL, which will look like https:\u002F\u002F\u003Cteam>.cloudfl","#step-2",{"@type":1647,"name":2587,"text":2588,"url":2589,"image":1943},"Set Up Traffic Routing","Click the profile for your VPS on the Devices dashboard. Scroll down to the 'Split Tunnels' section. Click the 'Manage' button and configure the settings as shown below. Replace the IP address if necessary. Exposing the address and host will route tr","#step-3",{"@type":1647,"name":2591,"text":2592,"url":2593},"Configure Firewall on the VPS","Enable the firewall to allow the '100.96.0.0\u002F12' subnet only, blocking all other public incoming access. bash Allow loopback traffic to avoid breaking local services: bash Reload the firewall and verify status: bash","#step-4",{"@type":1647,"name":2595,"text":2596,"url":2597},"Expose Hermes Agent to the Private Network","We will expose the Hermes Agent Web Dashboard to our private network and use the default authentication provider, Nous Research.","#step-5",{"@type":1647,"name":2599,"text":2600,"url":2601,"image":2445},"Install Cloudflare WARP Client on Desktop","Download the Cloudflare WARP client from Cloudflare's portal. Open and launch the Cloudflare WARP client after installation. Log in when prompted. A 'Success' page will be displayed after a successful login. The WARP client should now show it is conn","#step-6",{"@type":1647,"name":2603,"text":2604,"url":2605,"image":2504},"Install Cloudflare WARP Client on iOS Devices","Install Cloudflare One from the App Store. Open the Cloudflare One app and enter your team name when prompted. Log in using the same email address that was configured in the policy rule above. Once it is connected, it should look like the following:","#step-7",{"lastmod":2607},"2026-09-28",{"title":2609,"description":2571,"ogTitle":362,"ogDescription":2571,"twitterTitle":362,"twitterDescription":2571},"Secure Hermes Agent Access with Cloudflare Zero Trust",[1688,2611,1684,2612,2613],"Zero Trust","VPN","Tutorial","7w7yHDwhXSX7-e5xSvZ3rQ_6OcpB47010zvSqV1GJ9M",{"id":2616,"title":402,"author":424,"body":2617,"category":4037,"date":4039,"description":4040,"extension":1636,"image":4041,"imageAlt":4042,"isPublished":1059,"meta":4043,"minRead":2367,"navigation":1059,"path":63,"seo":4050,"stem":404,"tags":4052,"updatedAt":1673,"__hash__":4056},"article\u002Fen\u002Farticle\u002Fsync-obsidian-across-devices.md",{"type":426,"value":2618,"toc":4015},[2619,2622,2627,2636,2645,2662,2667,2671,2675,2680,2694,2710,2713,2717,2721,2728,2733,2737,2742,2799,2807,2839,2843,2850,2856,2863,2925,2928,2945,2952,2964,2968,2972,2983,2988,2994,2998,3019,3024,3038,3043,3048,3053,3067,3070,3075,3078,3083,3087,3092,3106,3110,3124,3135,3139,3144,3147,3157,3190,3194,3197,3339,3373,3379,3400,3411,3416,3420,3430,3501,3505,3510,3546,3677,3684,3690,3696,3702,3705,3711,3717,3731,3742,3749,3755,3762,3891,3897,3902,3905,3910,3913,3917,3922,3927,3933,3944,3954,3958,3969,3974,3980,3986,3989,4012],[429,2620,2621],{},"Obsidian is a local-first knowledge management app. Every note is a markdown file on your device and remains entirely under your control. However, we often want the same vault across our laptop, phone, and other devices, or to be able to access it through a web browser remotely.",[432,2623],{"src":2624,"alt":2625,"style":2626},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-multi-device-sync-illustration.webp","Illustration of Obsidian vault synchronized across multiple devices","max-width: 667px; width: 100%; height: auto;",[429,2628,2629,2630,2635],{},"A number of synchronisation solutions are available for Obsidian, but they all make trade-offs regarding conflict handling, encryption, or data sovereignty. ",[443,2631,2634],{"href":2632,"rel":2633},"https:\u002F\u002Fgithub.com\u002Fhjinco\u002Fsynch",[447],"Synch"," is an open-source application that synchronises your Obsidian vault with end-to-end encryption and automatic conflict handling on a self-hosted server.",[429,2637,2638,2639,2644],{},"While Obsidian's local-first approach works perfectly most of the time, we may still need to access our vault through a web browser remotely on some occasions. ",[443,2640,2643],{"href":2641,"rel":2642},"https:\u002F\u002Fgithub.com\u002FNystik-gh\u002Fignis",[447],"Ignis"," is an open-source application that runs Obsidian inside a web browser in a close-to-native format, allowing you to read and edit your vault from anywhere.",[429,2646,2647,2648,574,2650,2652,2653,2656,2657,2661],{},"In this guide, we will set up ",[440,2649,2634],{},[440,2651,2643],{}," on a ",[440,2654,2655],{},"VPS"," (Virtual Private Server), hosting them securely inside a ",[440,2658,2659],{},[443,2660,1691],{"href":363}," private network rather than exposing them to the open internet.",[432,2663],{"src":2664,"alt":2665,"style":2666},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-sync-cloudflare-zero-trust-architecture.webp","Architecture diagram of Obsidian sync using Cloudflare Zero Trust","max-width: 671px; width: 100%; height: auto;",[462,2668],{"description":2571,"image":2572,"image-alt":2573,"label":2669,"min-read":2670,"title":362,"to":363},"Related guide","8",[473,2672,2674],{"id":2673},"secure-obsidian-vault-synchronisation-with-synch","Secure Obsidian Vault Synchronisation with Synch",[429,2676,2677,2679],{},[440,2678,2634],{}," provides the following features:",[484,2681,2682,2685,2688,2691],{},[487,2683,2684],{},"Syncs your vault as soon as changes are detected",[487,2686,2687],{},"Encrypts vault data before upload",[487,2689,2690],{},"Allows restoration from version history",[487,2692,2693],{},"Includes automatic conflict handling",[429,2695,2696,2698,2699,2702,2703,2706,2707,2709],{},[440,2697,2634],{}," generates a random 32-byte ",[440,2700,2701],{},"vault key"," on your device, which is used to encrypt your vault data. When you create a remote vault, you choose a ",[440,2704,2705],{},"vault password","; this password is used to protect the ",[440,2708,2701],{}," so that the key can be stored securely on the server and unlocked on other devices.",[429,2711,2712],{},"Note conflict resolution is handled on your client devices rather than on the server. If two devices edit the same note simultaneously, the server keeps whichever version arrives first and flags the other device as out of date. The out-of-date device then automatically merges the newer version with its local changes before uploading the final merged note.",[874,2714,2716],{"id":2715},"set-up-synch-on-your-vps","Set Up Synch on Your VPS",[2125,2718,2720],{"id":2719},"create-a-domain-name","Create a Domain Name",[429,2722,2723,2724,2727],{},"Create an A record in Cloudflare and set its proxy status to ",[440,2725,2726],{},"DNS only"," (bypassing the Cloudflare CDN).",[432,2729],{"src":2730,"alt":2731,"style":2732},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fcloudflare-dns-a-record-synch-server.webp","Configuring a DNS A record for the Synch server in Cloudflare","max-width: 538px; width: 100%; height: auto;",[2125,2734,2736],{"id":2735},"install-synch-docker-on-ubuntu","Install Synch Docker on Ubuntu",[2738,2739,2741],"h5",{"id":2740},"clone-the-repository","Clone the Repository",[919,2743,2745],{"className":1027,"code":2744,"language":1029,"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",[494,2746,2747,2761,2766,2771,2779,2783,2788],{"__ignoreMap":424},[927,2748,2749,2752,2755,2758],{"class":929,"line":930},[927,2750,2751],{"class":1036},"git",[927,2753,2754],{"class":1040}," clone",[927,2756,2757],{"class":1040}," https:\u002F\u002Fgithub.com\u002Fhjinco\u002Fsynch.git",[927,2759,2760],{"class":937},"       \n",[927,2762,2763],{"class":929,"line":1056},[927,2764,2765],{"class":937},"        \n",[927,2767,2768],{"class":929,"line":1063},[927,2769,2770],{"class":1066},"# Navigate to the API folder\n",[927,2772,2773,2776],{"class":929,"line":1070},[927,2774,2775],{"class":958},"cd",[927,2777,2778],{"class":1040}," synch\u002Fapps\u002Fapi\n",[927,2780,2781],{"class":929,"line":1891},[927,2782,2765],{"class":937},[927,2784,2785],{"class":929,"line":1896},[927,2786,2787],{"class":1066},"# Copy the example environment file:\n",[927,2789,2790,2793,2796],{"class":929,"line":1902},[927,2791,2792],{"class":1036},"cp",[927,2794,2795],{"class":1040}," .env.example",[927,2797,2798],{"class":1040}," .env\n",[2738,2800,2802,2803,2806],{"id":2801},"edit-env-values","Edit ",[494,2804,2805],{},".env"," Values",[484,2808,2809,2815,2833],{},[487,2810,2811,2814],{},[494,2812,2813],{},"PUBLIC_URL=synch.pafor.me",": Enter the public domain name of your Synch server (the domain name created in the previous step).",[487,2816,2817,574,2820,2823,2824,2828,2829,2832],{},[494,2818,2819],{},"BETTER_AUTH_SECRET",[494,2821,2822],{},"SYNC_TOKEN_SECRET",": Generate secure keys using this ",[443,2825,2827],{"href":2826},"\u002Ftools\u002Fsecret-key-hex","online secret-key tool"," or by running ",[494,2830,2831],{},"openssl rand -hex 32"," twice in your terminal.",[487,2834,2835,2838],{},[494,2836,2837],{},"AUTH_ALLOWED_EMAILS",": A comma-separated list of the email addresses permitted to sign up and create accounts.",[2738,2840,2842],{"id":2841},"add-the-domain-to-caddyfile","Add the Domain to Caddyfile",[429,2844,2845,2846,460],{},"The details of how the Cloudflare DNS module is integrated with Caddy and started within a container can be found in our ",[443,2847,2849],{"href":2848},"\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues#_4-enable-https-with-caddy","self-hosting Buzz article",[462,2851],{"description":2852,"image":465,"image-alt":2853,"label":2854,"min-read":468,"title":2855,"to":2848},"Learn how to configure Caddy to automatically provision SSL\u002FTLS certificates using Cloudflare DNS challenges in Docker containers.","Configuring Caddy with Cloudflare DNS API token for automated SSL\u002FTLS certificate generation in a self-hosted workspace","Self-hosting guide","How to Enable HTTPS with Caddy and Cloudflare DNS",[429,2857,2858,2859,2862],{},"Include the ",[494,2860,2861],{},"SYNCH_DOMAIN"," directive in your Caddyfile, pointing to port 8787 (the port used by the Synch container):",[919,2864,2868],{"className":2865,"code":2866,"language":2867,"meta":424,"style":424},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\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","json",[494,2869,2870,2875,2883,2887,2891,2905,2910,2921],{"__ignoreMap":424},[927,2871,2872],{"class":929,"line":930},[927,2873,2874],{"class":941},"{\n",[927,2876,2877,2880],{"class":929,"line":1056},[927,2878,2879],{"class":937},"  acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN",[927,2881,2882],{"class":941},"}\n",[927,2884,2885],{"class":929,"line":1063},[927,2886,2882],{"class":937},[927,2888,2889],{"class":929,"line":1070},[927,2890,1060],{"emptyLinePlaceholder":1059},[927,2892,2893,2896,2899,2902],{"class":929,"line":1891},[927,2894,2895],{"class":941},"{",[927,2897,2898],{"class":937},"$SYNCH_DOMAIN",[927,2900,2901],{"class":941},"}",[927,2903,2904],{"class":941}," {\n",[927,2906,2907],{"class":929,"line":1896},[927,2908,2909],{"class":937},"  encode zstd gzip\n",[927,2911,2912,2915,2917],{"class":929,"line":1902},[927,2913,2914],{"class":937},"  reverse_proxy host.docker.internal",[927,2916,1253],{"class":941},[927,2918,2920],{"class":2919},"sbssI","8787\n",[927,2922,2923],{"class":929,"line":2238},[927,2924,2882],{"class":941},[429,2926,2927],{},"Start the container:",[919,2929,2931],{"className":1027,"code":2930,"language":1029,"meta":424,"style":424},"docker compose up -d\n",[494,2932,2933],{"__ignoreMap":424},[927,2934,2935,2937,2939,2942],{"class":929,"line":930},[927,2936,1148],{"class":1036},[927,2938,1151],{"class":1040},[927,2940,2941],{"class":1040}," up",[927,2943,2944],{"class":1040}," -d\n",[429,2946,2947,2948,2951],{},"Run the following ",[494,2949,2950],{},"curl"," command to check its availability:",[919,2953,2955],{"className":1027,"code":2954,"language":1029,"meta":424,"style":424},"curl https:\u002F\u002Fsynch.pafor.me\u002Fhealth\n",[494,2956,2957],{"__ignoreMap":424},[927,2958,2959,2961],{"class":929,"line":930},[927,2960,2950],{"class":1036},[927,2962,2963],{"class":1040}," https:\u002F\u002Fsynch.pafor.me\u002Fhealth\n",[874,2965,2967],{"id":2966},"connecting-obsidian-to-your-synch-server","Connecting Obsidian to Your Synch Server",[2125,2969,2971],{"id":2970},"install-the-synch-plugin-on-obsidian","Install the Synch Plugin on Obsidian",[429,2973,2974,2975,2978,2979,2982],{},"Open Obsidian Settings, navigate to ",[440,2976,2977],{},"Community plugins",", and click the ",[440,2980,2981],{},"'Browse'"," button:",[432,2984],{"src":2985,"alt":2986,"style":2987},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-community-plugins-browse.webp","Browsing community plugins in Obsidian settings","max-width: 523px; width: 100%; height: auto;",[429,2989,2990,2991,1253],{},"Search for and install ",[440,2992,2993],{},"'Synchrun'",[432,2995],{"src":2996,"alt":2997,"style":2732},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-install-synchrun-plugin.webp","Installing the Synchrun plugin in Obsidian",[429,2999,3000,3001,3003,3004,3007,3008,3011,3012,3015,3016,460],{},"Once ",[440,3002,2993],{}," is installed, open the plugin settings and enable ",[440,3005,3006],{},"'Use a self-hosted server'",". Then, enter ",[494,3009,3010],{},"https:\u002F\u002Fsynch.pafor.me"," in the ",[440,3013,3014],{},"'Server URL'"," field and click ",[440,3017,3018],{},"'Save'",[432,3020],{"src":3021,"alt":3022,"style":3023},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-synchrun-plugin-settings-self-hosted.webp","Configuring self-hosted server URL in Synchrun plugin settings","max-width: 525px; width: 100%; height: auto;",[429,3025,3026,3027,3030,3031,3034,3035,3037],{},"Click the ",[440,3028,3029],{},"'Sign in on this device'"," button under ",[440,3032,3033],{},"'Account'",". Next, sign up for an account using the email address you specified in your ",[494,3036,2837],{}," list; you will then be redirected to the following authorization page:",[432,3039],{"src":3040,"alt":3041,"style":3042},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynchrun-account-authorization-page.webp","Account authorization page for Synchrun","max-width: 494px; width: 100%; height: auto;",[429,3044,3026,3045,2982],{},[440,3046,3047],{},"'Allow Obsidian sign-in'",[432,3049],{"src":3050,"alt":3051,"style":3052},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynchrun-allow-obsidian-signin.webp","Allowing Obsidian sign-in for Synch","max-width: 498px; width: 100%; height: auto;",[429,3054,3026,3055,3058,3059,1342,3062],{},[440,3056,3057],{},"'Return to Obsidian'"," button, and then click ",[440,3060,3061],{},"'Create vault'",[432,3063],{"src":3064,"alt":3065,"style":3066},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-synchrun-create-remote-vault.webp","Creating a new remote vault in Synchrun","max-width: 496px; width: 100%; height: auto;",[429,3068,3069],{},"Enter a name and secure password to create your remote vault.",[432,3071],{"src":3072,"alt":3073,"style":3074},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-synchrun-vault-password-setup.webp","Setting up a secure password for the Obsidian remote vault","max-width: 500px; width: 100%; height: auto;",[429,3076,3077],{},"The synchronisation process will begin immediately and may take a while depending on the size of your vault. Once completed, your total storage usage will be displayed.",[432,3079],{"src":3080,"alt":3081,"style":3082},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-synchrun-sync-completed-storage.webp","Synchrun sync completed showing total storage used","max-width: 508px; width: 100%; height: auto;",[473,3084,3086],{"id":3085},"browser-based-obsidian-access-with-ignis","Browser-Based Obsidian Access with Ignis",[429,3088,3089,3091],{},[440,3090,2643],{}," replaces Obsidian's Electron APIs with Web APIs, which allows Obsidian's JavaScript code to be executed directly in a standard web browser. All your markdown files and attachments are stored directly in the host server's file system.",[429,3093,3094,3095,574,3100,3105],{},"However, there are a few limitations compared to the standalone Obsidian desktop application. Certain features or plugins that require Electron or Node.js APIs—which have no direct equivalent in a browser environment—will not work. Please refer to the Ignis ",[443,3096,3099],{"href":3097,"rel":3098},"https:\u002F\u002Fignis.thiefling.com\u002Fdocs\u002Fusing\u002Flimitations\u002F",[447],"Limitations",[443,3101,3104],{"href":3102,"rel":3103},"https:\u002F\u002Fignis.thiefling.com\u002Fdocs\u002Fusing\u002Fplugin-compatibility\u002F",[447],"Plugin compatibility"," guides for detailed compatibility listings.",[874,3107,3109],{"id":3108},"ignis-setup","Ignis Setup",[429,3111,3112,3113,3115,3116,3119,3120,3123],{},"We will install ",[440,3114,2643],{}," on our VPS using Docker, mounting it to the local ",[494,3117,3118],{},".\u002Fvaults"," folder. This vault directory will be synchronised using the ",[440,3121,3122],{},"Synch CLI"," to pull note updates from the remote vault we set up earlier.",[429,3125,3126,3127,3129,3130,3134],{},"Since ",[440,3128,2643],{}," does not have built-in authentication, it must be secured behind a ",[440,3131,3132],{},[443,3133,1691],{"href":363}," private network.",[2125,3136,3138],{"id":3137},"create-dns-record","Create DNS Record",[432,3140],{"src":3141,"alt":3142,"style":3143},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fcloudflare-dns-a-record-ignis.webp","Configuring a DNS A record for the Ignis web client in Cloudflare","max-width: 552px; width: 100%; height: auto;",[2125,3145,2842],{"id":3146},"add-the-domain-to-caddyfile-1",[429,3148,3149,3150,3153,3154,1253],{},"Add ",[494,3151,3152],{},"obsidian.pafor.me"," to your Caddyfile in the same way as ",[494,3155,3156],{},"synch.pafor.me",[919,3158,3160],{"className":2865,"code":3159,"language":2867,"meta":424,"style":424},"{$OBSIDIAN_DOMAIN} {\n  encode zstd gzip\n  reverse_proxy host.docker.internal:9898\n}\n",[494,3161,3162,3173,3177,3186],{"__ignoreMap":424},[927,3163,3164,3166,3169,3171],{"class":929,"line":930},[927,3165,2895],{"class":941},[927,3167,3168],{"class":937},"$OBSIDIAN_DOMAIN",[927,3170,2901],{"class":941},[927,3172,2904],{"class":941},[927,3174,3175],{"class":929,"line":1056},[927,3176,2909],{"class":937},[927,3178,3179,3181,3183],{"class":929,"line":1063},[927,3180,2914],{"class":937},[927,3182,1253],{"class":941},[927,3184,3185],{"class":2919},"9898\n",[927,3187,3188],{"class":929,"line":1070},[927,3189,2882],{"class":941},[2125,3191,3193],{"id":3192},"start-ignis-using-docker","Start Ignis using Docker",[429,3195,3196],{},"Save the following docker compose yml as ignis-docker-compose.yml on VPS:",[919,3198,3200],{"className":1316,"code":3199,"language":1318,"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",[494,3201,3202,3209,3216,3226,3233,3246,3253,3258,3265,3272,3279,3286,3293,3300,3307,3318,3323,3331],{"__ignoreMap":424},[927,3203,3204,3207],{"class":929,"line":930},[927,3205,3206],{"class":1328},"services",[927,3208,1342],{"class":941},[927,3210,3211,3214],{"class":929,"line":1056},[927,3212,3213],{"class":1328},"  ignis",[927,3215,1342],{"class":941},[927,3217,3218,3221,3223],{"class":929,"line":1063},[927,3219,3220],{"class":1328},"    image",[927,3222,1253],{"class":941},[927,3224,3225],{"class":1040}," nobbe\u002Fignis:latest\n",[927,3227,3228,3231],{"class":929,"line":1070},[927,3229,3230],{"class":1328},"    ports",[927,3232,1342],{"class":941},[927,3234,3235,3238,3241,3244],{"class":929,"line":1891},[927,3236,3237],{"class":941},"      -",[927,3239,3240],{"class":941}," \"",[927,3242,3243],{"class":1040},"9898:8080",[927,3245,1923],{"class":941},[927,3247,3248,3251],{"class":929,"line":1896},[927,3249,3250],{"class":1328},"    environment",[927,3252,1342],{"class":941},[927,3254,3255],{"class":929,"line":1902},[927,3256,3257],{"class":1066},"      # match these to your host user (run: id)\n",[927,3259,3260,3262],{"class":929,"line":2238},[927,3261,3237],{"class":941},[927,3263,3264],{"class":1040}," PUID=1000\n",[927,3266,3267,3269],{"class":929,"line":1667},[927,3268,3237],{"class":941},[927,3270,3271],{"class":1040}," PGID=1000\n",[927,3273,3274,3276],{"class":929,"line":2344},[927,3275,3237],{"class":941},[927,3277,3278],{"class":1040}," WS_ORIGINS=https:\u002F\u002Fobsidian.pafor.me\n",[927,3280,3281,3284],{"class":929,"line":2350},[927,3282,3283],{"class":1328},"    volumes",[927,3285,1342],{"class":941},[927,3287,3288,3290],{"class":929,"line":2356},[927,3289,3237],{"class":941},[927,3291,3292],{"class":1040}," .\u002Fvaults:\u002Fvaults\n",[927,3294,3295,3297],{"class":929,"line":2361},[927,3296,3237],{"class":941},[927,3298,3299],{"class":1040}," .\u002Fdata:\u002Fapp\u002Fdata\n",[927,3301,3302,3304],{"class":929,"line":2367},[927,3303,3237],{"class":941},[927,3305,3306],{"class":1040}," obsidian-app:\u002Fapp\u002Fobsidian-app\n",[927,3308,3310,3313,3315],{"class":929,"line":3309},15,[927,3311,3312],{"class":1328},"    restart",[927,3314,1253],{"class":941},[927,3316,3317],{"class":1040}," unless-stopped\n",[927,3319,3321],{"class":929,"line":3320},16,[927,3322,1060],{"emptyLinePlaceholder":1059},[927,3324,3326,3329],{"class":929,"line":3325},17,[927,3327,3328],{"class":1328},"volumes",[927,3330,1342],{"class":941},[927,3332,3334,3337],{"class":929,"line":3333},18,[927,3335,3336],{"class":1328},"  obsidian-app",[927,3338,1342],{"class":941},[484,3340,3341,3352,3366],{},[487,3342,3343,3344,3347,3348,3351],{},"Use port ",[494,3345,3346],{},"9898"," on the host, as ",[494,3349,3350],{},"8080"," is commonly used by other services.",[487,3353,3354,3355,3358,3359,574,3362,3365],{},"Run the ",[494,3356,3357],{},"id"," command on your VPS to verify your host user's ",[494,3360,3361],{},"UID",[494,3363,3364],{},"GID"," to ensure correct file system permissions.",[487,3367,3368,3369,3372],{},"Set ",[494,3370,3371],{},"WS_ORIGINS"," to only allow WebSocket connections originating from your specific domain name.",[429,3374,3375,3376,3378],{},"Start the ",[440,3377,2643],{}," docker:",[919,3380,3382],{"className":1027,"code":3381,"language":1029,"meta":424,"style":424},"docker compose -f ignis-docker-compose.yml up -d\n",[494,3383,3384],{"__ignoreMap":424},[927,3385,3386,3388,3390,3393,3396,3398],{"class":929,"line":930},[927,3387,1148],{"class":1036},[927,3389,1151],{"class":1040},[927,3391,3392],{"class":1040}," -f",[927,3394,3395],{"class":1040}," ignis-docker-compose.yml",[927,3397,2941],{"class":1040},[927,3399,2944],{"class":1040},[429,3401,3402,3403,3406,3407,3410],{},"When you navigate to your domain in a web browser, the ",[440,3404,3405],{},"'Vault Manager'"," will appear. It will be empty as no vaults are configured yet. We will set up the ",[440,3408,3409],{},"'Synch CLI'"," in the next section to synchronise contents from our remote vault.",[432,3412],{"src":3413,"alt":3414,"style":3415},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-vault-manager-empty.webp","Empty Vault Manager interface in Ignis web client","max-width: 466px; width: 100%; height: auto;",[2125,3417,3419],{"id":3418},"firewall-issue","Firewall Issue",[429,3421,3422,3423,3426,3427,1253],{},"By default, Docker automatically inserts its own DNAT and FORWARD rules, which route public traffic directly to active containers. This bypasses the standard Ubuntu UFW\u002Fiptables ",[494,3424,3425],{},"INPUT"," chain. To block external public traffic and keep the containers private, manually add the following rules to ",[494,3428,3429],{},"iptables",[919,3431,3433],{"className":1027,"code":3432,"language":1029,"meta":424,"style":424},"# Block all external public traffic\nsudo iptables -I DOCKER-USER -i ext_if -j DROP \n\n# Allow traffic only from your Cloudflare WARP client private IP\nsudo iptables -I DOCKER-USER -i ext_if -s 100.96.0.10 -j ACCEPT\n",[494,3434,3435,3440,3467,3471,3476],{"__ignoreMap":424},[927,3436,3437],{"class":929,"line":930},[927,3438,3439],{"class":1066},"# Block all external public traffic\n",[927,3441,3442,3444,3447,3450,3453,3456,3459,3462,3465],{"class":929,"line":1056},[927,3443,1859],{"class":1036},[927,3445,3446],{"class":1040}," iptables",[927,3448,3449],{"class":1040}," -I",[927,3451,3452],{"class":1040}," DOCKER-USER",[927,3454,3455],{"class":1040}," -i",[927,3457,3458],{"class":1040}," ext_if",[927,3460,3461],{"class":1040}," -j",[927,3463,3464],{"class":1040}," DROP",[927,3466,1992],{"class":937},[927,3468,3469],{"class":929,"line":1063},[927,3470,1060],{"emptyLinePlaceholder":1059},[927,3472,3473],{"class":929,"line":1070},[927,3474,3475],{"class":1066},"# Allow traffic only from your Cloudflare WARP client private IP\n",[927,3477,3478,3480,3482,3484,3486,3488,3490,3493,3496,3498],{"class":929,"line":1891},[927,3479,1859],{"class":1036},[927,3481,3446],{"class":1040},[927,3483,3449],{"class":1040},[927,3485,3452],{"class":1040},[927,3487,3455],{"class":1040},[927,3489,3458],{"class":1040},[927,3491,3492],{"class":1040}," -s",[927,3494,3495],{"class":2919}," 100.96.0.10",[927,3497,3461],{"class":1040},[927,3499,3500],{"class":1040}," ACCEPT\n",[2125,3502,3504],{"id":3503},"synch-cli-configuration","Synch CLI Configuration",[429,3506,597,3507,3509],{},[440,3508,3122],{}," is a headless tool that allows an Obsidian vault directory to be synchronised directly on remote servers without requiring the full desktop application to be installed.",[429,3511,3512,3513,3515,3516,3519,3520,3523,3524,3527,3528,743,3531,3534,3535,3538,3539,3542,3543,917],{},"Build the ",[440,3514,3122],{}," from your cloned ",[494,3517,3518],{},"synch"," repository. Building requires ",[440,3521,3522],{},"Node.js >= 22.5"," (as the CLI depends on ",[494,3525,3526],{},"node:sqlite"," and global browser APIs such as ",[494,3529,3530],{},"fetch",[494,3532,3533],{},"WebSocket",", and ",[494,3536,3537],{},"WebCrypto",") and ",[440,3540,3541],{},"pnpm"," (since the repository is structured as a pnpm workspace using version ",[494,3544,3545],{},"10.33.0",[919,3547,3549],{"className":1027,"code":3548,"language":1029,"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",[494,3550,3551,3556,3567,3574,3578,3583,3590,3594,3599,3612,3616,3621,3632,3661,3665,3670],{"__ignoreMap":424},[927,3552,3553],{"class":929,"line":930},[927,3554,3555],{"class":1066},"# Check versions\n",[927,3557,3558,3561,3564],{"class":929,"line":1056},[927,3559,3560],{"class":1036},"node",[927,3562,3563],{"class":1040}," --version",[927,3565,3566],{"class":1066},"   # must be >= 22.5\n",[927,3568,3569,3571],{"class":929,"line":1063},[927,3570,3541],{"class":1036},[927,3572,3573],{"class":1040}," --version\n",[927,3575,3576],{"class":929,"line":1070},[927,3577,1060],{"emptyLinePlaceholder":1059},[927,3579,3580],{"class":929,"line":1891},[927,3581,3582],{"class":1066},"# In the repos root\n",[927,3584,3585,3587],{"class":929,"line":1896},[927,3586,3541],{"class":1036},[927,3588,3589],{"class":1040}," install\n",[927,3591,3592],{"class":929,"line":1902},[927,3593,1060],{"emptyLinePlaceholder":1059},[927,3595,3596],{"class":929,"line":2238},[927,3597,3598],{"class":1066},"# Build the CLI bundle\n",[927,3600,3601,3603,3606,3609],{"class":929,"line":1667},[927,3602,3541],{"class":1036},[927,3604,3605],{"class":1040}," -C",[927,3607,3608],{"class":1040}," apps\u002Fcli",[927,3610,3611],{"class":1040}," build\n",[927,3613,3614],{"class":929,"line":2344},[927,3615,1060],{"emptyLinePlaceholder":1059},[927,3617,3618],{"class":929,"line":2350},[927,3619,3620],{"class":1066},"# After a successful build you have `apps\u002Fcli\u002Fdist\u002Fsynch.js`. Make it executable and put it on your PATH\n",[927,3622,3623,3626,3629],{"class":929,"line":2356},[927,3624,3625],{"class":1036},"chmod",[927,3627,3628],{"class":1040}," +x",[927,3630,3631],{"class":1040}," apps\u002Fcli\u002Fdist\u002Fsynch.js\n",[927,3633,3634,3637,3640,3642,3645,3648,3651,3653,3656,3659],{"class":929,"line":2361},[927,3635,3636],{"class":1036},"ln",[927,3638,3639],{"class":1040}," -sf",[927,3641,3240],{"class":941},[927,3643,3644],{"class":937},"$PWD",[927,3646,3647],{"class":1040},"\u002Fapps\u002Fcli\u002Fdist\u002Fsynch.js",[927,3649,3650],{"class":941},"\"",[927,3652,3240],{"class":941},[927,3654,3655],{"class":937},"$HOME",[927,3657,3658],{"class":1040},"\u002F.local\u002Fbin\u002Fsynch",[927,3660,1923],{"class":941},[927,3662,3663],{"class":929,"line":2367},[927,3664,1060],{"emptyLinePlaceholder":1059},[927,3666,3667],{"class":929,"line":3309},[927,3668,3669],{"class":1066},"# Verification\n",[927,3671,3672,3674],{"class":929,"line":3320},[927,3673,3518],{"class":1036},[927,3675,3676],{"class":1040}," --help\n",[429,3678,3679,3680,3683],{},"Since the Synch CLI is running on the same VPS as your Synch remote vault, it can connect to the local API server directly. If you are configuring a different server, run ",[494,3681,3682],{},"synch login --api-url \u003Cremote-synch-api-url>"," to define your target API endpoint.",[429,3685,3686],{},[432,3687],{"alt":3688,"src":3689},"Running synch login with custom API URL in terminal","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynch-login-api-url-terminal.webp",[429,3691,1798,3692,3695],{},[494,3693,3694],{},"synch login"," in your terminal, and you will receive an authentication URL:",[429,3697,3698],{},[432,3699],{"alt":3700,"src":3701},"Terminal output showing the authentication URL for Synch CLI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynch-login-auth-url-terminal.webp",[429,3703,3704],{},"Log in via the web page using the same email address registered with your Obsidian desktop Synchrun plugin.",[429,3706,3707],{},[432,3708],{"alt":3709,"src":3710},"Successful web login for Synch CLI authorization","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynch-web-login-success.webp",[429,3712,1798,3713,3716],{},[494,3714,3715],{},"synch vault connect --vault ~\u002Fvaults\u002F\u003Cvaultname> --vault-id asadqe-7b29-4677-fsad-234asdafasd"," to link your local vault directory on the VPS to the remote vault.",[429,3718,3719,3720,3723,3724,3727,3728,917],{},"The remote vault ID can be found inside the ",[440,3721,3722],{},"Synchrun"," plugin settings by clicking ",[440,3725,3726],{},"'Manage remote vaults'",". This will display a web page showing a list of your remote vaults, each identified by a unique GUID (e.g., ",[494,3729,3730],{},"123e4567-e89b-12d3-a456-426614174000",[429,3732,3733,3738],{},[432,3734],{"src":3735,"alt":3736,"style":3737},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynchrun-manage-remote-vaults.webp","Managing remote vaults in the Synchrun plugin","max-width: 582px; width: 100%; height: auto;",[432,3739],{"alt":3740,"src":3741},"Locating the unique remote vault ID in Synchrun","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynchrun-remote-vault-id.webp",[429,3743,3744,3745,3748],{},"Enter your vault password when prompted to establish the link. Once connected, run ",[494,3746,3747],{},"synch sync --vault ~\u002Fvaults\u002F\u003Cvault-name>"," to perform your initial synchronisation. This first run may take some time depending on your vault size.",[429,3750,3751],{},[432,3752],{"alt":3753,"src":3754},"Initial vault synchronization progress in Synch CLI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fsynch-cli-initial-sync-progress.webp",[429,3756,3757,3758,3761],{},"To automate this, set up and enable a systemd service to run ",[494,3759,3760],{},"synch watch"," continuously, ensuring changes are synchronised instantly on boot:",[919,3763,3765],{"className":1027,"code":3764,"language":1029,"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",[494,3766,3767,3783,3787,3792,3797,3802,3806,3810,3815,3820,3825,3830,3835,3840,3844,3849,3853,3857,3861,3867,3876],{"__ignoreMap":424},[927,3768,3769,3771,3774,3777,3780],{"class":929,"line":930},[927,3770,1859],{"class":1036},[927,3772,3773],{"class":1040}," tee",[927,3775,3776],{"class":1040}," \u002Fetc\u002Fsystemd\u002Fsystem\u002Fsynch-watch.service",[927,3778,3779],{"class":941}," \u003C\u003C",[927,3781,3782],{"class":941},"'EOF'\n",[927,3784,3785],{"class":929,"line":1056},[927,3786,2302],{"class":1040},[927,3788,3789],{"class":929,"line":1063},[927,3790,3791],{"class":1040},"Description=Synch vault watcher\n",[927,3793,3794],{"class":929,"line":1070},[927,3795,3796],{"class":1040},"After=network-online.target\n",[927,3798,3799],{"class":929,"line":1891},[927,3800,3801],{"class":1040},"Wants=network-online.target\n",[927,3803,3804],{"class":929,"line":1896},[927,3805,1060],{"emptyLinePlaceholder":1059},[927,3807,3808],{"class":929,"line":1902},[927,3809,2321],{"class":1040},[927,3811,3812],{"class":929,"line":2238},[927,3813,3814],{"class":1040},"Type=simple\n",[927,3816,3817],{"class":929,"line":1667},[927,3818,3819],{"class":1040},"User=\u003Cusername>\n",[927,3821,3822],{"class":929,"line":2344},[927,3823,3824],{"class":1040},"ExecStart=\u002Fhome\u002F\u003Cusername>\u002F.local\u002Fbin\u002Fsynch watch --vault \u002Fhome\u002F\u003Cusername>\u002Fvaults\u002F\u003Cvault-name>\n",[927,3826,3827],{"class":929,"line":2350},[927,3828,3829],{"class":1040},"WorkingDirectory=\u002Fhome\u002F\u003Cusername>\u002Fvaults\n",[927,3831,3832],{"class":929,"line":2356},[927,3833,3834],{"class":1040},"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",[927,3836,3837],{"class":929,"line":2361},[927,3838,3839],{"class":1040},"Environment=\"HOME=\u002Fhome\u002F\u003Cusername>\"\n",[927,3841,3842],{"class":929,"line":2367},[927,3843,2341],{"class":1040},[927,3845,3846],{"class":929,"line":3309},[927,3847,3848],{"class":1040},"RestartSec=5\n",[927,3850,3851],{"class":929,"line":3320},[927,3852,1060],{"emptyLinePlaceholder":1059},[927,3854,3855],{"class":929,"line":3325},[927,3856,2364],{"class":1040},[927,3858,3859],{"class":929,"line":3333},[927,3860,2370],{"class":1040},[927,3862,3864],{"class":929,"line":3863},19,[927,3865,3866],{"class":941},"EOF\n",[927,3868,3870,3872,3874],{"class":929,"line":3869},20,[927,3871,1859],{"class":1036},[927,3873,1862],{"class":1040},[927,3875,2389],{"class":1040},[927,3877,3879,3881,3883,3885,3888],{"class":929,"line":3878},21,[927,3880,1859],{"class":1036},[927,3882,1862],{"class":1040},[927,3884,1989],{"class":1040},[927,3886,3887],{"class":1040}," --now",[927,3889,3890],{"class":1040}," synch-watch.service\n",[429,3892,3893,3894,3896],{},"Open ",[494,3895,3152],{}," in your web browser. You will find that the user interface and layout are virtually identical to the desktop app:",[432,3898],{"src":3899,"alt":3900,"style":3901},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-web-interface-desktop-view.webp","Ignis web interface displaying the Obsidian vault on desktop","max-width: 593px; width: 100%; height: auto;",[429,3903,3904],{},"Clicking the settings icon reveals that almost all core configurations are intact, though your community plugins will need to be reinstalled:",[432,3906],{"src":3907,"alt":3908,"style":3909},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-settings-community-plugins.webp","Community plugins settings in the Ignis web interface","max-width: 597px; width: 100%; height: auto;",[429,3911,3912],{},"To test the setup, you can add a new note via the web interface:",[432,3914],{"src":3915,"alt":3916,"style":3909},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-create-new-note-web.webp","Creating a new markdown note via the Ignis web interface",[429,3918,3919,3920,460],{},"The note is immediately synchronised back to your Obsidian desktop app. Note that empty folders do not appear in ",[440,3921,2643],{},[432,3923],{"src":3924,"alt":3925,"style":3926},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fobsidian-desktop-synced-note.webp","Newly created note successfully synced to the Obsidian desktop app","max-width: 502px; width: 100%; height: auto;",[429,3928,3929,3930,3932],{},"Viewing ",[494,3931,3152],{}," on a mobile web browser:",[429,3934,3935,3940],{},[432,3936],{"src":3937,"alt":3938,"style":3939},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-mobile-view-sidebar.webp","Sidebar navigation of the Ignis web client on a mobile device","max-width: 269px; width: 100%; height: auto;",[432,3941],{"src":3942,"alt":3943,"style":3939},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002Fignis-mobile-view-editor.webp","Markdown note editor of the Ignis web client on a mobile device",[429,3945,3946,3947,3949,3950,3953],{},"When you delete a note on ",[440,3948,2643],{},", it is safely moved to your local vault's ",[494,3951,3952],{},"~\u002Fvaults\u002F\u003Cvault-name>\u002F.trash"," folder.",[473,3955,3957],{"id":3956},"final-thoughts-on-self-hosted-vaults","Final Thoughts on Self-Hosted Vaults",[429,3959,3960,3961,574,3963,3965,3966,3968],{},"Together, ",[440,3962,2634],{},[440,3964,2643],{}," make your primary Obsidian vault seamlessly available across all of your devices, completely hosted on infrastructure under your direct control. Positioning these services inside a ",[440,3967,1691],{}," private network ensures that your personal notes are entirely shielded from the public internet.",[429,3970,3971,3973],{},[440,3972,2643],{}," is not intended to fully replace the native Obsidian desktop app. Instead, it serves as a lightweight, temporary web client for accessing and editing your vault when you are away from your main computer. For day-to-day writing and extensive vault management, the native Obsidian application remains the most comfortable choice.",[429,3975,3976,3977,3979],{},"Because Synch uses end-to-end encryption, your remote vault password must be highly secure to protect against brute-force guessing attacks. It is critical that you never lose this password—the server does not store the unencrypted ",[440,3978,2701],{},", and if forgotten, your data will be completely unrecoverable. Additionally, ensure that your VPS instance, alongside any automated snapshots or backups, is properly secured and maintained.",[429,3981,3982,3983,3985],{},"While ",[440,3984,2634],{},"'s encrypted version history and deleted-file recovery tools cover most accidental losses, keeping a separate, independent backup of your Obsidian vault is still highly recommended.",[473,3987,3988],{"id":1582},"References",[484,3990,3991,3998,4005],{},[487,3992,3993],{},[443,3994,3997],{"href":3995,"rel":3996},"https:\u002F\u002Fsynch.run\u002Fself-hosting-docker\u002F",[447],"Synch Deploy with Docker Compose",[487,3999,4000],{},[443,4001,4004],{"href":4002,"rel":4003},"https:\u002F\u002Fignis.thiefling.com\u002Fdocs\u002Fserver\u002Fdeploy\u002F",[447],"Ignis Deploy with Docker",[487,4006,4007],{},[443,4008,4011],{"href":4009,"rel":4010},"https:\u002F\u002Fsynch.run\u002Fblog\u002Fencryption-and-decryption\u002F",[447],"How does end-to-end encryption work in Synch?",[1611,4013,4014],{},"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":1056,"depth":1063,"links":4016},[4017,4026,4035,4036],{"id":2673,"depth":1056,"text":2674,"children":4018},[4019,4023],{"id":2715,"depth":1063,"text":2716,"children":4020},[4021,4022],{"id":2719,"depth":1070,"text":2720},{"id":2735,"depth":1070,"text":2736},{"id":2966,"depth":1063,"text":2967,"children":4024},[4025],{"id":2970,"depth":1070,"text":2971},{"id":3085,"depth":1056,"text":3086,"children":4027},[4028],{"id":3108,"depth":1063,"text":3109,"children":4029},[4030,4031,4032,4033,4034],{"id":3137,"depth":1070,"text":3138},{"id":3146,"depth":1070,"text":2842},{"id":3192,"depth":1070,"text":3193},{"id":3418,"depth":1070,"text":3419},{"id":3503,"depth":1070,"text":3504},{"id":3956,"depth":1056,"text":3957},{"id":1582,"depth":1056,"text":3988},[4038],"productivity","2026-09-15","Securely synchronise Obsidian vaults across your devices and access notes on the web using self-hosted Synch and Ignis within Cloudflare Zero Trust.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSync%20Obsidian%20Across%20Devices\u002FEN-Sync-Obsidian-Across-Devices.webp","Securely synchronising Obsidian vaults across multiple devices using self-hosted Synch and Ignis web client inside Cloudflare Zero Trust",{"schemaOrg":4044,"robots":1665,"sitemap":4048},[4045,4047],{"@type":4046,"headline":402,"description":4040,"image":4041},"Article",{"@type":1644,"name":402,"description":4040,"image":4041},{"lastmod":4049},"2026-09-16",{"title":4051,"description":4040,"ogTitle":402,"ogDescription":4040,"twitterTitle":402,"twitterDescription":4040},"Secure Self-Hosted Obsidian Sync with Synch & Ignis",[4053,4054,4055,2611],"Self-hosting","Obsidian","Sync","NmSkE1ri49cYPhoFTZtGO8tViPA-_S4FK-pDGfoT1H4",{"id":4058,"title":382,"author":424,"body":4059,"category":6188,"date":6189,"description":464,"extension":1636,"image":465,"imageAlt":466,"isPublished":1059,"meta":6190,"minRead":3320,"navigation":1059,"path":53,"seo":6212,"stem":384,"tags":6214,"updatedAt":1673,"__hash__":6218},"article\u002Fen\u002Farticle\u002Fself-hosting-buzz-as-the-workspace-where-ai-agents-become-colleagues.md",{"type":426,"value":4060,"toc":6158},[4061,4064,4070,4075,4079,4082,4120,4124,4130,4168,4172,4176,4190,4196,4198,4202,4206,4221,4227,4277,4303,4307,4314,4320,4324,4327,4537,4541,4581,4586,4593,4601,4649,4655,4681,4685,4689,4716,4742,4747,4789,4798,5069,5073,5116,5121,5128,5132,5136,5160,5163,5169,5172,5176,5184,5190,5193,5199,5205,5229,5235,5241,5244,5250,5254,5257,5260,5263,5269,5272,5278,5284,5290,5295,5299,5310,5317,5323,5326,5332,5336,5343,5349,5355,5359,5367,5431,5444,5499,5502,5572,5578,5592,5598,5602,5647,5653,5656,5662,5665,5671,5675,5690,5706,5712,5809,5812,5818,5829,5875,5881,5887,5899,5915,5918,5924,5928,5937,5959,5969,6067,6077,6083,6090,6096,6099,6105,6108,6114,6118,6121,6125,6155],[429,4062,4063],{},"Context fragmentation is a frustrating hurdle when working with multiple AI agents. With conversations scattered across different tools, you end up acting as a human router by copying conversations from Claude Code to paste into Gemini CLI, then copying from Gemini CLI to paste into Hermes Agent. This friction increases when human colleagues are on the same team.",[429,4065,4066],{},[432,4067],{"alt":4068,"src":4069},"The user interface of the Buzz collaborative workspace showing chat channels and active AI agents","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-workspace-interface.webp",[429,4071,4072,4074],{},[440,4073,454],{},", an open-source collaboration workspace, brings human teams and AI agents together into a single, unified environment. Here, human colleagues and AI agents share the same task and project history, seamlessly handing work off to one another.",[473,4076,4078],{"id":4077},"what-is-blocks-buzz-the-collaborative-ai-agent-workspace","What is Block's Buzz? The Collaborative AI Agent Workspace",[429,4080,4081],{},"Buzz is an open-source collaboration workspace from Block (Jack Dorsey's company) where humans and AI agents share the same channels and projects. It offers the following key features:",[484,4083,4084,4090,4096,4102,4108,4114],{},[487,4085,4086,4089],{},[440,4087,4088],{},"Shared context:"," Channels are where humans and agents collaborate with one another. All conversational and project history is contained within the channel.",[487,4091,4092,4095],{},[440,4093,4094],{},"Agent-to-agent communication:"," Agents can communicate with each other, even across different machines. An agent can @-mention another agent to hand off work or cross-check code.",[487,4097,4098,4101],{},[440,4099,4100],{},"Mention-driven activation:"," Agents only act when @-mentioned, otherwise staying quiet. When mentioned, an agent reads the relevant context in the channel and start working.",[487,4103,4104,4107],{},[440,4105,4106],{},"Unified identity system:"," Humans and agents use the same identity system, authenticated via cryptographic keys.",[487,4109,4110,4113],{},[440,4111,4112],{},"Delegated commands:"," You can grant human colleagues permission to command your agents, allowing the entire team to brief and leverage each other's digital helpers.",[487,4115,4116,4119],{},[440,4117,4118],{},"Self-hosted servers:"," Because you host the server, your data remains fully under your control. You choose who joins and define your own operational rules.",[473,4121,4123],{"id":4122},"the-cryptographic-nostr-powered-architecture-of-buzz","The Cryptographic, Nostr-Powered Architecture of Buzz",[429,4125,4126],{},[432,4127],{"alt":4128,"src":4129},"Cryptographic, Nostr-powered architectural diagram of the Buzz collaboration workspace","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-nostr-cryptographic-architecture.webp",[484,4131,4132,4138,4144,4150,4156,4162],{},[487,4133,4134,4137],{},[440,4135,4136],{},"The Nostr relay acts as the server:"," Messages, workflows, repositories, and other events are cryptographically signed, verified, and stored on a Nostr relay server. The Nostr protocol natively supports communication over WebSockets and REST APIs.",[487,4139,4140,4143],{},[440,4141,4142],{},"Unified cryptographic identity:"," Both humans and agents authenticate using their own cryptographic keys. This identity remains client-side and is never stored on the server.",[487,4145,4146,4149],{},[440,4147,4148],{},"First-class agent membership:"," Every agent possesses its own identity, channel memberships, and audit trail. Agents connect to the workspace using the Agent Communication Protocol (ACP).",[487,4151,4152,4155],{},[440,4153,4154],{},"Decentralised Git repositories:"," Code repositories are stored on S3 compatible object storage, while tasks, pull requests, and code reviews are tracked within the Nostr event log. Consequently, a Buzz Git repository is hosted on the Nostr relay rather than GitHub.",[487,4157,4158,4161],{},[440,4159,4160],{},"The Buzz app is a Nostr client:"," Buzz is separate from the Nostr relay; it is a desktop\u002Fmobile client application that connects to the relay's URL.",[487,4163,4164,4167],{},[440,4165,4166],{},"Infrastructure stack:"," A PostgreSQL database handles event storage and full-text search, Redis manages pub\u002Fsub messaging, and S3 compatible MinIO is used for media storage.",[473,4169,4171],{"id":4170},"how-to-self-host-blocks-buzz-relay-on-a-linux-vps","How to Self-Host Block's Buzz Relay on a Linux VPS",[874,4173,4175],{"id":4174},"_0-prerequisites","0. Prerequisites",[484,4177,4178,4181,4184,4187],{},[487,4179,4180],{},"A Linux VPS",[487,4182,4183],{},"A domain pointing at your server",[487,4185,4186],{},"Docker and the Docker Compose plugin",[487,4188,4189],{},"Cloudflare account (free tier)",[429,4191,4192,4193,4195],{},"In this guide, we will run the Nostr relay on an Ubuntu VPS behind a ",[443,4194,1691],{"href":363}," private network. The stack is four services in Docker Compose, relay, PostgreSQL, Redis and MinIO.",[462,4197],{"description":2571,"image":2572,"image-alt":2573,"label":2669,"min-read":2670,"title":362,"to":363},[874,4199,4201],{"id":4200},"_1-cloudflare-dns-and-api-token","1. Cloudflare DNS and API Token",[2125,4203,4205],{"id":4204},"create-a-cloudflare-api-token","Create a Cloudflare API Token",[532,4207,4208,4215],{},[487,4209,4210,4211,4214],{},"Click on the top right ",[440,4212,4213],{},"Profile"," from the user icon dropdown menu.",[487,4216,4217,4218,460],{},"Click on ",[440,4219,4220],{},"API Tokens",[429,4222,4223],{},[432,4224],{"alt":4225,"src":4226},"Cloudflare user profile page showing the API Tokens creation menu","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fcloudflare-profile-api-tokens.webp",[532,4228,4229,4235,4242,4262,4267,4271,4274],{"start":1063},[487,4230,4231,4232,460],{},"Click ",[440,4233,4234],{},"Create Token",[487,4236,4237,4238,4241],{},"Use the ",[440,4239,4240],{},"Edit zone DNS"," template.",[487,4243,4244,4245],{},"Configure the template as follows:\n",[484,4246,4247,4253],{},[487,4248,4249,4252],{},[440,4250,4251],{},"Permissions",": Zone — DNS — Edit",[487,4254,4255,4258,4259],{},[440,4256,4257],{},"Zone Resources",": Include — Specific zone — ",[494,4260,4261],{},"example.com",[487,4263,4231,4264,460],{},[440,4265,4266],{},"Continue to summary",[487,4268,4231,4269,460],{},[440,4270,4234],{},[487,4272,4273],{},"Copy the generated token as it won't be shown when the page is closed.",[487,4275,4276],{},"Test the generated token in your terminal to ensure it works:",[919,4278,4280],{"className":1027,"code":4279,"language":1029,"meta":424,"style":424},"curl \"https:\u002F\u002Fapi.cloudflare.com\u002Fclient\u002Fv4\u002Fuser\u002Ftokens\u002Fverify\" -H \"Authorization: Bearer YOUR_TOKEN_HERE\"\n",[494,4281,4282],{"__ignoreMap":424},[927,4283,4284,4286,4288,4291,4293,4296,4298,4301],{"class":929,"line":930},[927,4285,2950],{"class":1036},[927,4287,3240],{"class":941},[927,4289,4290],{"class":1040},"https:\u002F\u002Fapi.cloudflare.com\u002Fclient\u002Fv4\u002Fuser\u002Ftokens\u002Fverify",[927,4292,3650],{"class":941},[927,4294,4295],{"class":1040}," -H",[927,4297,3240],{"class":941},[927,4299,4300],{"class":1040},"Authorization: Bearer YOUR_TOKEN_HERE",[927,4302,1923],{"class":941},[2125,4304,4306],{"id":4305},"dns-records","DNS Records",[484,4308,4309],{},[487,4310,4311,4312,460],{},"Create an A record and set it to ",[440,4313,2726],{},[429,4315,4316],{},[432,4317],{"alt":4318,"src":4319},"Configuring a DNS A record for the Buzz domain in Cloudflare dashboard with proxy status set to 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",[874,4321,4323],{"id":4322},"_2-install-docker-on-ubuntu","2. Install Docker on Ubuntu",[429,4325,4326],{},"Run the following commands to install Docker on Ubuntu:",[919,4328,4330],{"className":1027,"code":4329,"language":1029,"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",[494,4331,4332,4337,4365,4369,4374,4416,4420,4425,4435,4439,4444,4465,4469,4474,4485,4489,4494,4500,4504,4518,4522,4527],{"__ignoreMap":424},[927,4333,4334],{"class":929,"line":930},[927,4335,4336],{"class":1066},"# Add Docker's official GPG key and set up the Docker repository\n",[927,4338,4339,4341,4344,4347,4350,4353,4356,4359,4362],{"class":929,"line":1056},[927,4340,2950],{"class":1036},[927,4342,4343],{"class":1040}," -fsSL",[927,4345,4346],{"class":1040}," https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu\u002Fgpg",[927,4348,4349],{"class":941}," |",[927,4351,4352],{"class":1036}," sudo",[927,4354,4355],{"class":1040}," gpg",[927,4357,4358],{"class":1040}," --dearmor",[927,4360,4361],{"class":1040}," -o",[927,4363,4364],{"class":1040}," \u002Fusr\u002Fshare\u002Fkeyrings\u002Fdocker-archive-keyring.gpg\n",[927,4366,4367],{"class":929,"line":1063},[927,4368,1060],{"emptyLinePlaceholder":1059},[927,4370,4371],{"class":929,"line":1070},[927,4372,4373],{"class":1066},"# Add the official Docker repository\n",[927,4375,4376,4379,4381,4384,4387,4390,4393,4396,4399,4401,4403,4405,4407,4410,4413],{"class":929,"line":1891},[927,4377,4378],{"class":958},"echo",[927,4380,3240],{"class":941},[927,4382,4383],{"class":1040},"deb [arch=amd64 signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fdocker-archive-keyring.gpg] https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu ",[927,4385,4386],{"class":941},"$(",[927,4388,4389],{"class":1036},"lsb_release",[927,4391,4392],{"class":1040}," -cs",[927,4394,4395],{"class":941},")",[927,4397,4398],{"class":1040}," stable",[927,4400,3650],{"class":941},[927,4402,4349],{"class":941},[927,4404,4352],{"class":1036},[927,4406,3773],{"class":1040},[927,4408,4409],{"class":1040}," \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.list",[927,4411,4412],{"class":941}," >",[927,4414,4415],{"class":1040}," \u002Fdev\u002Fnull\n",[927,4417,4418],{"class":929,"line":1896},[927,4419,1060],{"emptyLinePlaceholder":1059},[927,4421,4422],{"class":929,"line":1902},[927,4423,4424],{"class":1066},"# Update package list\n",[927,4426,4427,4429,4432],{"class":929,"line":2238},[927,4428,1859],{"class":1036},[927,4430,4431],{"class":1040}," apt",[927,4433,4434],{"class":1040}," update\n",[927,4436,4437],{"class":929,"line":1667},[927,4438,1060],{"emptyLinePlaceholder":1059},[927,4440,4441],{"class":929,"line":2344},[927,4442,4443],{"class":1066},"# Install Docker Engine, Docker Community Edition, and containerd runtime\n",[927,4445,4446,4448,4450,4453,4456,4459,4462],{"class":929,"line":2350},[927,4447,1859],{"class":1036},[927,4449,4431],{"class":1040},[927,4451,4452],{"class":1040}," install",[927,4454,4455],{"class":1040}," docker-ce",[927,4457,4458],{"class":1040}," docker-ce-cli",[927,4460,4461],{"class":1040}," containerd.io",[927,4463,4464],{"class":1040}," -y\n",[927,4466,4467],{"class":929,"line":2356},[927,4468,1060],{"emptyLinePlaceholder":1059},[927,4470,4471],{"class":929,"line":2361},[927,4472,4473],{"class":1066},"# Start automatically when the system boots\n",[927,4475,4476,4478,4480,4482],{"class":929,"line":2367},[927,4477,1859],{"class":1036},[927,4479,1862],{"class":1040},[927,4481,1989],{"class":1040},[927,4483,4484],{"class":1040}," docker\n",[927,4486,4487],{"class":929,"line":3309},[927,4488,1060],{"emptyLinePlaceholder":1059},[927,4490,4491],{"class":929,"line":3320},[927,4492,4493],{"class":1066},"# Verify docker is installed\n",[927,4495,4496,4498],{"class":929,"line":3325},[927,4497,1148],{"class":1036},[927,4499,3573],{"class":1040},[927,4501,4502],{"class":929,"line":3333},[927,4503,1060],{"emptyLinePlaceholder":1059},[927,4505,4506,4508,4510,4512,4515],{"class":929,"line":3863},[927,4507,1859],{"class":1036},[927,4509,4431],{"class":1040},[927,4511,4452],{"class":1040},[927,4513,4514],{"class":1040}," -y",[927,4516,4517],{"class":1040}," docker-compose-plugin\n",[927,4519,4520],{"class":929,"line":3869},[927,4521,1060],{"emptyLinePlaceholder":1059},[927,4523,4524],{"class":929,"line":3878},[927,4525,4526],{"class":1066},"# Verify the compose plugin is installed\n",[927,4528,4530,4532,4534],{"class":929,"line":4529},22,[927,4531,1148],{"class":1036},[927,4533,1151],{"class":1040},[927,4535,4536],{"class":1040}," version\n",[874,4538,4540],{"id":4539},"_3-clone-and-configure","3. Clone and configure",[919,4542,4544],{"className":1027,"code":4543,"language":1029,"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",[494,4545,4546,4555,4559,4566,4574],{"__ignoreMap":424},[927,4547,4548,4550,4552],{"class":929,"line":930},[927,4549,2751],{"class":1036},[927,4551,2754],{"class":1040},[927,4553,4554],{"class":1040}," https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz.git\n",[927,4556,4557],{"class":929,"line":1056},[927,4558,1060],{"emptyLinePlaceholder":1059},[927,4560,4561,4563],{"class":929,"line":1063},[927,4562,2775],{"class":958},[927,4564,4565],{"class":1040}," buzz\u002Fdeploy\u002Fcompose\n",[927,4567,4568,4570,4572],{"class":929,"line":1070},[927,4569,2792],{"class":1036},[927,4571,2795],{"class":1040},[927,4573,2798],{"class":1040},[927,4575,4576,4579],{"class":929,"line":1891},[927,4577,4578],{"class":1036},"nano",[927,4580,2798],{"class":1040},[429,4582,2802,4583,4585],{},[494,4584,2805],{}," in groups:",[484,4587,4588],{},[487,4589,4590],{},[440,4591,4592],{},"Domain:",[919,4594,4599],{"className":4595,"code":4597,"language":4598},[4596],"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",[494,4600,4597],{"__ignoreMap":424},[484,4602,4603,4612],{},[487,4604,4605,992,4608,4611],{},[440,4606,4607],{},"Owner key:",[494,4609,4610],{},"RELAY_OWNER_PUBKEY"," requires your 64-character hex public key. Generate an identity in the desktop app first ('Create a new identity key' → copy your public ID, which is in npub format), then convert it to hex.",[487,4613,4614,4617],{},[440,4615,4616],{},"Secrets:",[484,4618,4619,4629,4643],{},[487,4620,4621,4622,4625,4626,4628],{},"Generate secrets using this ",[443,4623,4624],{"href":2826},"online tool"," or with ",[494,4627,2831],{}," (run it seven times)",[487,4630,4631,4632,4635,4636,743,4639,4642],{},"Replace every ",[494,4633,4634],{},"CHANGE_ME"," placeholder: ",[494,4637,4638],{},"BUZZ_RELAY_PRIVATE_KEY",[494,4640,4641],{},"BUZZ_GIT_HOOK_HMAC_SECRET",", the Postgres\u002FRedis\u002FTypesense passwords, and the S3 access\u002Fsecret keys.",[487,4644,4645,4646,460],{},"Leftover placeholders are the most common cause of container restart loops; verify yours with ",[494,4647,4648],{},"grep CHANGE_ME .env",[919,4650,4653],{"className":4651,"code":4652,"language":4598},[4596],"    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",[494,4654,4652],{"__ignoreMap":424},[484,4656,4657],{},[487,4658,4659,4662],{},[440,4660,4661],{},"Others:",[484,4663,4664,4670],{},[487,4665,3149,4666,4669],{},[494,4667,4668],{},"CLOUDFLARE_API_TOKEN"," as an environment variable and assign the API token generated earlier. This is required for Caddy.",[487,4671,4672,4673,743,4675,3534,4678,460],{},"Buzz ships with open defaults — anyone who knows your relay URL can authenticate and join. Set ",[494,4674,4610],{},[494,4676,4677],{},"BUZZ_REQUIRE_RELAY_MEMBERSHIP=true",[494,4679,4680],{},"BUZZ_REQUIRE_AUTH_TOKEN=true",[874,4682,4684],{"id":4683},"_4-enable-https-with-caddy","4. Enable HTTPS with Caddy",[2125,4686,4688],{"id":4687},"build-a-custom-caddy-image-with-the-cloudflare-dns-module","Build a Custom Caddy Image with the Cloudflare DNS Module",[484,4690,4691,4702,4713],{},[487,4692,4693,4694,4697,4698,4701],{},"We set up DNS-01 with Cloudflare for Caddy. DNS-01 works by having the plugin write a TXT record ",[494,4695,4696],{},"_acme-challenge.buzz.pafor.me"," to the ",[440,4699,4700],{},"public DNS",";",[487,4703,4704,4705,4708,4709,4712],{},"Let's Encrypt then looks the record up from the public internet to verify domain control. This means ",[494,4706,4707],{},"pafor.me"," must be a public zone in your Cloudflare account — not just a private hostname that only exists in Zero Trust \u002F WARP private DNS. If ",[494,4710,4711],{},"buzz.pafor.me"," is only resolved privately and there is no public zone, DNS-01 will fail, requiring a different approach.",[487,4714,4715],{},"Add the following to the Caddyfile:",[919,4717,4719],{"className":1316,"code":4718,"language":1318,"meta":424,"style":424},"{\n  acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}\n}\n",[494,4720,4721,4725,4738],{"__ignoreMap":424},[927,4722,4723],{"class":929,"line":930},[927,4724,2874],{"class":941},[927,4726,4727,4730,4733,4736],{"class":929,"line":1056},[927,4728,4729],{"class":1040},"  acme_dns cloudflare",[927,4731,4732],{"class":941}," {",[927,4734,4735],{"class":1040},"env.CLOUDFLARE_API_TOKEN",[927,4737,2882],{"class":941},[927,4739,4740],{"class":929,"line":1063},[927,4741,2882],{"class":941},[484,4743,4744],{},[487,4745,4746],{},"Create a Dockerfile.caddy with the following content, which is required by compose.caddy.yml:",[919,4748,4750],{"className":1316,"code":4749,"language":1318,"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",[494,4751,4752,4757,4761,4766,4771,4775,4780,4784],{"__ignoreMap":424},[927,4753,4754],{"class":929,"line":930},[927,4755,4756],{"class":1040},"FROM caddy:2-builder AS builder\n",[927,4758,4759],{"class":929,"line":1056},[927,4760,1060],{"emptyLinePlaceholder":1059},[927,4762,4763],{"class":929,"line":1063},[927,4764,4765],{"class":1040},"RUN xcaddy build \\\n",[927,4767,4768],{"class":929,"line":1070},[927,4769,4770],{"class":1040},"    --with github.com\u002Fcaddy-dns\u002Fcloudflare\n",[927,4772,4773],{"class":929,"line":1891},[927,4774,1060],{"emptyLinePlaceholder":1059},[927,4776,4777],{"class":929,"line":1896},[927,4778,4779],{"class":1040},"FROM caddy:2-alpine\n",[927,4781,4782],{"class":929,"line":1902},[927,4783,1060],{"emptyLinePlaceholder":1059},[927,4785,4786],{"class":929,"line":2238},[927,4787,4788],{"class":1040},"COPY --from=builder \u002Fusr\u002Fbin\u002Fcaddy \u002Fusr\u002Fbin\u002Fcaddy\n",[484,4790,4791],{},[487,4792,4793,4794,4797],{},"Modify ",[494,4795,4796],{},"compose.caddy.yml"," to use the image with the Cloudflare module and pass the Cloudflare API token:",[919,4799,4801],{"className":1316,"code":4800,"language":1318,"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",[494,4802,4803,4809,4816,4828,4832,4839,4846,4856,4866,4875,4882,4889,4899,4905,4915,4925,4931,4942,4953,4959,4966,4973,4980,4989,4997,5005,5010,5017,5025,5033,5044,5052,5059],{"__ignoreMap":424},[927,4804,4805,4807],{"class":929,"line":930},[927,4806,3206],{"class":1328},[927,4808,1342],{"class":941},[927,4810,4811,4814],{"class":929,"line":1056},[927,4812,4813],{"class":1328},"  relay",[927,4815,1342],{"class":941},[927,4817,4818,4820,4822,4825],{"class":929,"line":1063},[927,4819,3230],{"class":1328},[927,4821,1253],{"class":941},[927,4823,4824],{"class":933}," !reset",[927,4826,4827],{"class":941}," []\n",[927,4829,4830],{"class":929,"line":1070},[927,4831,1060],{"emptyLinePlaceholder":1059},[927,4833,4834,4837],{"class":929,"line":1891},[927,4835,4836],{"class":1328},"  caddy",[927,4838,1342],{"class":941},[927,4840,4841,4844],{"class":929,"line":1896},[927,4842,4843],{"class":1328},"    build",[927,4845,1342],{"class":941},[927,4847,4848,4851,4853],{"class":929,"line":1902},[927,4849,4850],{"class":1328},"      context",[927,4852,1253],{"class":941},[927,4854,4855],{"class":2919}," .\n",[927,4857,4858,4861,4863],{"class":929,"line":2238},[927,4859,4860],{"class":1328},"      dockerfile",[927,4862,1253],{"class":941},[927,4864,4865],{"class":1040}," Dockerfile.caddy\n",[927,4867,4868,4870,4872],{"class":929,"line":1667},[927,4869,3220],{"class":1328},[927,4871,1253],{"class":941},[927,4873,4874],{"class":1040}," buzz-caddy:cloudflare\n",[927,4876,4877,4880],{"class":929,"line":2344},[927,4878,4879],{"class":1328},"    depends_on",[927,4881,1342],{"class":941},[927,4883,4884,4887],{"class":929,"line":2350},[927,4885,4886],{"class":1328},"      relay",[927,4888,1342],{"class":941},[927,4890,4891,4894,4896],{"class":929,"line":2356},[927,4892,4893],{"class":1328},"        condition",[927,4895,1253],{"class":941},[927,4897,4898],{"class":1040}," service_healthy\n",[927,4900,4901,4903],{"class":929,"line":2361},[927,4902,3250],{"class":1328},[927,4904,1342],{"class":941},[927,4906,4907,4910,4912],{"class":929,"line":2367},[927,4908,4909],{"class":1328},"      BUZZ_DOMAIN",[927,4911,1253],{"class":941},[927,4913,4914],{"class":1040}," ${BUZZ_DOMAIN:?set BUZZ_DOMAIN}\n",[927,4916,4917,4920,4922],{"class":929,"line":3309},[927,4918,4919],{"class":1328},"      CLOUDFLARE_API_TOKEN",[927,4921,1253],{"class":941},[927,4923,4924],{"class":1040}," ${CLOUDFLARE_API_TOKEN:?set CLOUDFLARE_API_TOKEN}\n",[927,4926,4927,4929],{"class":929,"line":3320},[927,4928,3230],{"class":1328},[927,4930,1342],{"class":941},[927,4932,4933,4935,4937,4940],{"class":929,"line":3325},[927,4934,3237],{"class":941},[927,4936,3240],{"class":941},[927,4938,4939],{"class":1040},"${CADDY_HTTP_PORT:-80}:80",[927,4941,1923],{"class":941},[927,4943,4944,4946,4948,4951],{"class":929,"line":3333},[927,4945,3237],{"class":941},[927,4947,3240],{"class":941},[927,4949,4950],{"class":1040},"${CADDY_HTTPS_PORT:-443}:443",[927,4952,1923],{"class":941},[927,4954,4955,4957],{"class":929,"line":3863},[927,4956,3283],{"class":1328},[927,4958,1342],{"class":941},[927,4960,4961,4963],{"class":929,"line":3869},[927,4962,3237],{"class":941},[927,4964,4965],{"class":1040}," .\u002FCaddyfile:\u002Fetc\u002Fcaddy\u002FCaddyfile:ro\n",[927,4967,4968,4970],{"class":929,"line":3878},[927,4969,3237],{"class":941},[927,4971,4972],{"class":1040}," buzz-caddy-data:\u002Fdata\n",[927,4974,4975,4977],{"class":929,"line":4529},[927,4976,3237],{"class":941},[927,4978,4979],{"class":1040}," buzz-caddy-config:\u002Fconfig\n",[927,4981,4983,4985,4987],{"class":929,"line":4982},23,[927,4984,3312],{"class":1328},[927,4986,1253],{"class":941},[927,4988,3317],{"class":1040},[927,4990,4992,4995],{"class":929,"line":4991},24,[927,4993,4994],{"class":1328},"    networks",[927,4996,1342],{"class":941},[927,4998,5000,5002],{"class":929,"line":4999},25,[927,5001,3237],{"class":941},[927,5003,5004],{"class":1040}," buzz-net\n",[927,5006,5008],{"class":929,"line":5007},26,[927,5009,1060],{"emptyLinePlaceholder":1059},[927,5011,5013,5015],{"class":929,"line":5012},27,[927,5014,3328],{"class":1328},[927,5016,1342],{"class":941},[927,5018,5020,5023],{"class":929,"line":5019},28,[927,5021,5022],{"class":1328},"  buzz-caddy-data",[927,5024,1342],{"class":941},[927,5026,5028,5031],{"class":929,"line":5027},29,[927,5029,5030],{"class":1328},"    labels",[927,5032,1342],{"class":941},[927,5034,5036,5039,5041],{"class":929,"line":5035},30,[927,5037,5038],{"class":1328},"      com.buzz.volume",[927,5040,1253],{"class":941},[927,5042,5043],{"class":1040}," caddy-data\n",[927,5045,5047,5050],{"class":929,"line":5046},31,[927,5048,5049],{"class":1328},"  buzz-caddy-config",[927,5051,1342],{"class":941},[927,5053,5055,5057],{"class":929,"line":5054},32,[927,5056,5030],{"class":1328},[927,5058,1342],{"class":941},[927,5060,5062,5064,5066],{"class":929,"line":5061},33,[927,5063,5038],{"class":1328},[927,5065,1253],{"class":941},[927,5067,5068],{"class":1040}," caddy-config\n",[2125,5070,5072],{"id":5071},"start-the-docker-containers","Start the Docker containers",[919,5074,5076],{"className":1027,"code":5075,"language":1029,"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",[494,5077,5078,5098,5102,5107],{"__ignoreMap":424},[927,5079,5080,5082,5084,5086,5089,5091,5094,5096],{"class":929,"line":930},[927,5081,1148],{"class":1036},[927,5083,1151],{"class":1040},[927,5085,3392],{"class":1040},[927,5087,5088],{"class":1040}," compose.yml",[927,5090,3392],{"class":1040},[927,5092,5093],{"class":1040}," compose.caddy.yml",[927,5095,2941],{"class":1040},[927,5097,2944],{"class":1040},[927,5099,5100],{"class":929,"line":1056},[927,5101,1060],{"emptyLinePlaceholder":1059},[927,5103,5104],{"class":929,"line":1063},[927,5105,5106],{"class":1066},"#Check the Docker status\n",[927,5108,5109,5111,5113],{"class":929,"line":1070},[927,5110,1148],{"class":1036},[927,5112,1151],{"class":1040},[927,5114,5115],{"class":1040}," ps\n",[432,5117],{"src":5118,"alt":5119,"style":5120},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fdocker-compose-ps-status-terminal.webp","Terminal window displaying running containers for Buzz services via docker compose ps","max-width: 700px; width: 100%; height: auto;",[429,5122,5123,5124,5127],{},"Open your web browser and navigate to ",[494,5125,5126],{},"http:\u002F\u002Fbuzz.pafor.me"," to verify that the relay is running.",[432,5129],{"src":5130,"alt":5131,"style":3074},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-relay-running-browser-verification.webp","Browser verification showing successful response from self-hosted Block's Buzz relay",[874,5133,5135],{"id":5134},"step-5-back-up-from-day-one","Step 5: Back up from day one",[919,5137,5139],{"className":1027,"code":5138,"language":1029,"meta":424,"style":424},"mkdir -p \u002Fbuzz_backups\ncrontab -e\n",[494,5140,5141,5152],{"__ignoreMap":424},[927,5142,5143,5146,5149],{"class":929,"line":930},[927,5144,5145],{"class":1036},"mkdir",[927,5147,5148],{"class":1040}," -p",[927,5150,5151],{"class":1040}," \u002Fbuzz_backups\n",[927,5153,5154,5157],{"class":929,"line":1056},[927,5155,5156],{"class":1036},"crontab",[927,5158,5159],{"class":1040}," -e\n",[429,5161,5162],{},"Add a nightly database dump cron job:",[919,5164,5167],{"className":5165,"code":5166,"language":4598},[4596],"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",[494,5168,5166],{"__ignoreMap":424},[429,5170,5171],{},"Note: Treat BUZZ_RELAY_PRIVATE_KEY as permanent. Events signed by it will fail verification if the key changes; a restored database paired with a fresh key is not treated as the same relay.",[473,5173,5175],{"id":5174},"setting-up-the-buzz-desktop-client-and-nostr-identities","Setting Up the Buzz Desktop Client and Nostr Identities",[429,5177,5178,5179,5183],{},"Download the Buzz desktop app from ",[443,5180,5181],{"href":5181,"rel":5182},"https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz\u002Freleases",[447]," and start it. Fill in the profile details until you reach the \"Join or create a community\" page.",[429,5185,5186],{},[432,5187],{"alt":5188,"src":5189},"Buzz Desktop Client initial setup screen for joining or creating a community","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-setup-community.webp",[429,5191,5192],{},"Click \"Join a community\" and copy your public key.",[429,5194,5195],{},[432,5196],{"alt":5197,"src":5198},"Buzz client display showing public key identity before joining community","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,5200,5201,5202,5204],{},"Run the following command on the ",[440,5203,2655],{}," to add yourself as the first member:",[919,5206,5208],{"className":1027,"code":5207,"language":1029,"meta":424,"style":424},"docker compose exec relay buzz-admin add-member --pubkey npub1yourkeyhere\n",[494,5209,5210],{"__ignoreMap":424},[927,5211,5212,5214,5216,5218,5220,5222,5224,5226],{"class":929,"line":930},[927,5213,1148],{"class":1036},[927,5215,1151],{"class":1040},[927,5217,1154],{"class":1040},[927,5219,1157],{"class":1040},[927,5221,1160],{"class":1040},[927,5223,1163],{"class":1040},[927,5225,1166],{"class":1040},[927,5227,5228],{"class":1040}," npub1yourkeyhere\n",[429,5230,3149,5231,5234],{},[494,5232,5233],{},"wss:\u002F\u002Fbuzz.pafor.me"," as the community URL and click \"Next\".",[429,5236,5237],{},[432,5238],{"alt":5239,"src":5240},"Entering the self-hosted community relay URL in the Buzz desktop app","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,5242,5243],{},"Enter a name and click the Next button.",[429,5245,5246],{},[432,5247],{"alt":5248,"src":5249},"Profile configuration screen in Buzz app to enter display name","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-profile-name-input.webp",[874,5251,5253],{"id":5252},"channels-and-agents","Channels and Agents",[429,5255,5256],{},"Channels are task groups or project groups. Create a channel per task or project and pull the humans and agents in.",[429,5258,5259],{},"Everything within a channel is shared automatically, eliminating the need to brief each member individually. Every agent can be mentioned using @ and reads the relevant messages. Also, agents can @ each other.",[429,5261,5262],{},"Let's send a DM to a preconfigured agent",[429,5264,5265],{},[432,5266],{"alt":5267,"src":5268},"Sending direct message to an AI agent in the Buzz collaborative desktop client","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-dm-agent.webp",[429,5270,5271],{},"Let's create a channel and add some agents to it",[429,5273,5274],{},[432,5275],{"alt":5276,"src":5277},"Creating a new task or project channel inside the Buzz desktop app","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,5279,5280],{},[432,5281],{"alt":5282,"src":5283},"Adding human members and AI agents to the newly created channel","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,5285,5286],{},[432,5287],{"alt":5288,"src":5289},"Active channel view displaying consolidated chat history and project tasks","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-channel-view.webp",[432,5291],{"src":5292,"alt":5293,"style":5294},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-channel-active-agents.webp","Detail view of active AI agents integrated into the collaborative project channel","max-width: 367px; width: 100%; height: auto;",[874,5296,5298],{"id":5297},"enable-agent-runtimes","Enable Agent Runtimes",[429,5300,5301,5302,5305,5306,5309],{},"Preset runtimes rely on auto-discovery detecting launcher binaries (e.g. ",[494,5303,5304],{},"hermes-acp",") in standard directories like ",[494,5307,5308],{},"~\u002F.local\u002Fbin",". If a tool was installed in a non-standard location, Buzz cannot resolve it.",[429,5311,5312,5313,5316],{},"For Kimi Code, the agent ID is kimi, and Buzz looks for its binary at ",[494,5314,5315],{},"~\u002F.local\u002Fbin\u002Fkimi",". A symbolic link does the job:",[919,5318,5321],{"className":5319,"code":5320,"language":4598},[4596],"ln -s kimi-cli \u002FUsers\u002F\u003Cuser>\u002F.local\u002Fbin\u002Fkimi\n",[494,5322,5320],{"__ignoreMap":424},[429,5324,5325],{},"Kimi Code now appears under Agent runtimes.",[429,5327,5328],{},[432,5329],{"alt":5330,"src":5331},"Buzz application settings displaying configured AI Agent runtimes including Kimi","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-settings-agent-runtimes-list.webp",[874,5333,5335],{"id":5334},"projects-and-repositories","Projects and Repositories",[429,5337,5338,5339,5342],{},"Enable the '",[440,5340,5341],{},"Projects","' feature in Settings → Experiments first:",[429,5344,5345],{},[432,5346],{"alt":5347,"src":5348},"Enabling experimental Projects feature in the Buzz desktop settings tab","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-settings-experiments-projects.webp",[429,5350,5351,5352,5354],{},"Currently, a project must be created using the ",[494,5353,1178],{}," (though direct project creation from the UI is planned for a future release).",[2125,5356,5358],{"id":5357},"install-buzz-cli","Install buzz-cli",[429,5360,5361,5362,5364,5365,1253],{},"Run the following commands to install ",[494,5363,1178],{}," on the ",[440,5366,2655],{},[919,5368,5370],{"className":1027,"code":5369,"language":1029,"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",[494,5371,5372,5383,5390,5403],{"__ignoreMap":424},[927,5373,5374,5376,5378,5380],{"class":929,"line":930},[927,5375,1859],{"class":1036},[927,5377,4431],{"class":1040},[927,5379,4452],{"class":1040},[927,5381,5382],{"class":1040}," cargo\n",[927,5384,5385,5387],{"class":929,"line":1056},[927,5386,2775],{"class":958},[927,5388,5389],{"class":1040}," ~\u002Fbuzz\n",[927,5391,5392,5395,5397,5400],{"class":929,"line":1063},[927,5393,5394],{"class":1036},"cargo",[927,5396,4452],{"class":1040},[927,5398,5399],{"class":1040}," --path",[927,5401,5402],{"class":1040}," crates\u002Fbuzz-cli\n",[927,5404,5405,5407,5410,5413,5416,5419,5422,5425,5428],{"class":929,"line":1070},[927,5406,4378],{"class":958},[927,5408,5409],{"class":941}," '",[927,5411,5412],{"class":1040},"export PATH=\"$HOME\u002F.cargo\u002Fbin:$PATH\"",[927,5414,5415],{"class":941},"'",[927,5417,5418],{"class":941}," >>",[927,5420,5421],{"class":1040}," ~\u002F.bashrc",[927,5423,5424],{"class":941}," &&",[927,5426,5427],{"class":958}," source",[927,5429,5430],{"class":1040}," ~\u002F.bashrc\n",[429,5432,5433,5434,5437,5438,5440,5441,5443],{},"Generate a pair of private and public keys using the ",[443,5435,4624],{"href":5436},"\u002Ftools\u002Fnostr-key-generator"," or ",[494,5439,1178],{},". This pair is the identity of the ",[494,5442,1178],{}," in Nostr relay.",[919,5445,5447],{"className":1027,"code":5446,"language":1029,"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",[494,5448,5449,5471,5475,5480],{"__ignoreMap":424},[927,5450,5451,5453,5456,5459,5462,5465,5468],{"class":929,"line":930},[927,5452,1148],{"class":1036},[927,5454,5455],{"class":1040}," run",[927,5457,5458],{"class":1040}," --rm",[927,5460,5461],{"class":1040}," --entrypoint",[927,5463,5464],{"class":1040}," \u002Fusr\u002Flocal\u002Fbin\u002Fbuzz-admin",[927,5466,5467],{"class":1040}," ghcr.io\u002Fblock\u002Fbuzz:main",[927,5469,5470],{"class":1040}," generate-key\n",[927,5472,5473],{"class":929,"line":1056},[927,5474,1060],{"emptyLinePlaceholder":1059},[927,5476,5477],{"class":929,"line":1063},[927,5478,5479],{"class":1066},"# Use the generated Public Key\n",[927,5481,5482,5484,5486,5488,5490,5492,5494,5496],{"class":929,"line":1070},[927,5483,1148],{"class":1036},[927,5485,1151],{"class":1040},[927,5487,1154],{"class":1040},[927,5489,1157],{"class":1040},[927,5491,1160],{"class":1040},[927,5493,1163],{"class":1040},[927,5495,1166],{"class":1040},[927,5497,5498],{"class":1040}," generated_Public_key\n",[429,5500,5501],{},"Configure the CLI:",[919,5503,5505],{"className":1027,"code":5504,"language":1029,"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",[494,5506,5507,5512,5543,5547],{"__ignoreMap":424},[927,5508,5509],{"class":929,"line":930},[927,5510,5511],{"class":1066},"# Copy the Secret key as the BUZZ_PRIVATE_KEY\n",[927,5513,5514,5516,5518,5521,5523,5526,5529,5532,5535,5538,5540],{"class":929,"line":1056},[927,5515,4378],{"class":958},[927,5517,5409],{"class":941},[927,5519,5520],{"class":1040},"export BUZZ_PRIVATE_KEY=\"nsec1...\"",[927,5522,5415],{"class":941},[927,5524,5525],{"class":941},"  >>",[927,5527,5528],{"class":1040}," \u002Fhome\u002F",[927,5530,5531],{"class":941},"\u003C",[927,5533,5534],{"class":1040},"use",[927,5536,5537],{"class":937},"r",[927,5539,1221],{"class":941},[927,5541,5542],{"class":1040},"\u002F.bashrc\n",[927,5544,5545],{"class":929,"line":1063},[927,5546,1060],{"emptyLinePlaceholder":1059},[927,5548,5549,5551,5553,5556,5558,5560,5562,5564,5566,5568,5570],{"class":929,"line":1070},[927,5550,4378],{"class":958},[927,5552,5409],{"class":941},[927,5554,5555],{"class":1040},"export BUZZ_RELAY_URL=\"wss:\u002F\u002Fbuzz.pafor.me\"",[927,5557,5415],{"class":941},[927,5559,5525],{"class":941},[927,5561,5528],{"class":1040},[927,5563,5531],{"class":941},[927,5565,5534],{"class":1040},[927,5567,5537],{"class":937},[927,5569,1221],{"class":941},[927,5571,5542],{"class":1040},[429,5573,5574,5575,5577],{},"Run the following command to verify ",[494,5576,1178],{}," is configured properly:",[919,5579,5581],{"className":1027,"code":5580,"language":1029,"meta":424,"style":424},"buzz channels list\n",[494,5582,5583],{"__ignoreMap":424},[927,5584,5585,5587,5589],{"class":929,"line":930},[927,5586,1201],{"class":1036},[927,5588,1204],{"class":1040},[927,5590,5591],{"class":1040}," list\n",[429,5593,5594],{},[432,5595],{"alt":5596,"src":5597},"Terminal command execution verifying buzz-cli configuration by listing active channels","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-cli-channels-list-terminal.webp",[2125,5599,5601],{"id":5600},"create-a-project-with-buzz-cli","Create a Project with buzz-cli",[919,5603,5605],{"className":1027,"code":5604,"language":1029,"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",[494,5606,5607,5612],{"__ignoreMap":424},[927,5608,5609],{"class":929,"line":930},[927,5610,5611],{"class":1066},"# --channel refers to the UUID of the channel\n",[927,5613,5614,5616,5619,5622,5625,5628,5631,5633,5636,5638,5640,5642,5645],{"class":929,"line":1056},[927,5615,1201],{"class":1036},[927,5617,5618],{"class":1040}," repos",[927,5620,5621],{"class":1040}," create",[927,5623,5624],{"class":1040}," --id",[927,5626,5627],{"class":1040}," TestKOA",[927,5629,5630],{"class":1040}," --name",[927,5632,5409],{"class":941},[927,5634,5635],{"class":1040},"Display Name",[927,5637,5415],{"class":941},[927,5639,1209],{"class":1040},[927,5641,3240],{"class":941},[927,5643,5644],{"class":1040},"bd92b3d1-8fac-441c-a9ac-2b2f3aac5c5b",[927,5646,1923],{"class":941},[429,5648,5649,5650,5652],{},"A project can only be removed by its owner. Because the \"Display Name\" project was created by the ",[494,5651,1178],{},", which lacks a removal command, it cannot be deleted this way.",[429,5654,5655],{},"Check back the Buzz desktop app to verify the project is created.",[429,5657,5658],{},[432,5659],{"alt":5660,"src":5661},"Buzz desktop application projects view confirming successful project creation","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-project-view.webp",[429,5663,5664],{},"Once a project is available in Projects, more projects can be added using the \"+\" button at the top right corner.",[429,5666,5667],{},[432,5668],{"alt":5669,"src":5670},"Adding new developer projects using the plus icon in Buzz desktop client","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-add-project-button.webp",[2125,5672,5674],{"id":5673},"check-in-existing-git-repositories","Check In Existing Git Repositories",[429,5676,2493,5677,5680,5681,5684,5685,1253],{},[494,5678,5679],{},"git-credential-nostr"," on the machine where git repositories are. It requires ",[440,5682,5683],{},"git 2.46+"," and the Rust toolchain. Refer to this ",[443,5686,5689],{"href":5687,"rel":5688},"https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz\u002Ftree\u002Fmain\u002Fcrates\u002Fgit-credential-nostr",[447],"Readme",[919,5691,5693],{"className":1027,"code":5692,"language":1029,"meta":424,"style":424},"cargo install --path crates\u002Fgit-credential-nostr\n",[494,5694,5695],{"__ignoreMap":424},[927,5696,5697,5699,5701,5703],{"class":929,"line":930},[927,5698,5394],{"class":1036},[927,5700,4452],{"class":1040},[927,5702,5399],{"class":1040},[927,5704,5705],{"class":1040}," crates\u002Fgit-credential-nostr\n",[429,5707,5708,5709,5711],{},"Set up ",[494,5710,5679],{}," for Buzz relay authorisation:",[919,5713,5715],{"className":1027,"code":5714,"language":1029,"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",[494,5716,5717,5722,5738,5751,5755,5760,5769,5796],{"__ignoreMap":424},[927,5718,5719],{"class":929,"line":930},[927,5720,5721],{"class":1066},"# 1. Register the helper and enable per-path credentials.\n",[927,5723,5724,5726,5729,5732,5735],{"class":929,"line":1056},[927,5725,2751],{"class":1036},[927,5727,5728],{"class":1040}," config",[927,5730,5731],{"class":1040}," --global",[927,5733,5734],{"class":1040}," credential.helper",[927,5736,5737],{"class":1040}," nostr\n",[927,5739,5740,5742,5744,5746,5749],{"class":929,"line":1063},[927,5741,2751],{"class":1036},[927,5743,5728],{"class":1040},[927,5745,5731],{"class":1040},[927,5747,5748],{"class":1040}," credential.useHttpPath",[927,5750,1353],{"class":941},[927,5752,5753],{"class":929,"line":1070},[927,5754,1060],{"emptyLinePlaceholder":1059},[927,5756,5757],{"class":929,"line":1891},[927,5758,5759],{"class":1066},"# 2. Store your nsec in a key file (must be 0600). Replace \"nsec1...\" with your private key\n",[927,5761,5762,5764,5766],{"class":929,"line":1896},[927,5763,5145],{"class":1036},[927,5765,5148],{"class":1040},[927,5767,5768],{"class":1040}," ~\u002F.nostr\n",[927,5770,5771,5773,5775,5778,5780,5782,5785,5787,5790,5793],{"class":929,"line":1902},[927,5772,4378],{"class":958},[927,5774,3240],{"class":941},[927,5776,5777],{"class":1040},"nsec1...",[927,5779,3650],{"class":941},[927,5781,4412],{"class":941},[927,5783,5784],{"class":1040}," ~\u002F.nostr\u002Fkey",[927,5786,5424],{"class":941},[927,5788,5789],{"class":1036}," chmod",[927,5791,5792],{"class":2919}," 600",[927,5794,5795],{"class":1040}," ~\u002F.nostr\u002Fkey\n",[927,5797,5798,5800,5802,5804,5807],{"class":929,"line":2238},[927,5799,2751],{"class":1036},[927,5801,5728],{"class":1040},[927,5803,5731],{"class":1040},[927,5805,5806],{"class":1040}," nostr.keyfile",[927,5808,5795],{"class":1040},[429,5810,5811],{},"Create a repo on the Buzz relay:",[919,5813,5816],{"className":5814,"code":5815,"language":4598},[4596],"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",[494,5817,5815],{"__ignoreMap":424},[429,5819,5820,5821,5824,5825,5828],{},"On your first ",[494,5822,5823],{},"git push",", you will encounter a ",[494,5826,5827],{},"remote: missing Authorization header"," error. To resolve this, you need to bind the repository ID to a Buzz channel, as channel membership dictates Git write permissions (ACLs):",[919,5830,5832],{"className":1027,"code":5831,"language":1029,"meta":424,"style":424},"buzz repos bind --id koa-email-routing --channel \u003CCHANNEL_UUID>\n\n# push the code again\ngit push\n",[494,5833,5834,5859,5863,5868],{"__ignoreMap":424},[927,5835,5836,5838,5840,5843,5845,5848,5850,5852,5854,5856],{"class":929,"line":930},[927,5837,1201],{"class":1036},[927,5839,5618],{"class":1040},[927,5841,5842],{"class":1040}," bind",[927,5844,5624],{"class":1040},[927,5846,5847],{"class":1040}," koa-email-routing",[927,5849,1209],{"class":1040},[927,5851,1212],{"class":941},[927,5853,1215],{"class":1040},[927,5855,1218],{"class":937},[927,5857,5858],{"class":941},">\n",[927,5860,5861],{"class":929,"line":1056},[927,5862,1060],{"emptyLinePlaceholder":1059},[927,5864,5865],{"class":929,"line":1063},[927,5866,5867],{"class":1066},"# push the code again\n",[927,5869,5870,5872],{"class":929,"line":1070},[927,5871,2751],{"class":1036},[927,5873,5874],{"class":1040}," push\n",[429,5876,5877,5878,5880],{},"Checking the project in the Buzz desktop app shows the following, because the app needs ",[440,5879,5683],{}," — launching the app directly may pick up an older version of Git:",[429,5882,5883],{},[432,5884],{"alt":5885,"src":5886},"Buzz client rendering Git loading error due to outdated local Git version below 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,5888,5889,5890,5893,5894,460],{},"Export the PATH via ",[494,5891,5892],{},"launchctl setenv PATH \"\u002Fopt\u002Fhomebrew\u002Fbin:\u002Fusr\u002Flocal\u002Fbin:\u002Fusr\u002Fbin:\u002Fbin:\u002Fusr\u002Fsbin:\u002Fsbin\""," in the shell profile and launch the Buzz app from the shell. Refer to this ",[443,5895,5898],{"href":5896,"rel":5897},"https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz\u002Fissues\u002F5348",[447],"issue",[919,5900,5902],{"className":1027,"code":5901,"language":1029,"meta":424,"style":424},"open -a Buzz\n",[494,5903,5904],{"__ignoreMap":424},[927,5905,5906,5909,5912],{"class":929,"line":930},[927,5907,5908],{"class":1036},"open",[927,5910,5911],{"class":1040}," -a",[927,5913,5914],{"class":1040}," Buzz\n",[429,5916,5917],{},"Check back the Projects in the Buzz app, the repository details are now loaded.",[429,5919,5920],{},[432,5921],{"alt":5922,"src":5923},"Buzz desktop interface with successfully loaded Git repository details and commit logs","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-desktop-client-repository-details-loaded.webp",[473,5925,5927],{"id":5926},"syncing-ai-agents-with-the-buzz-mobile-app-via-qr-code","Syncing AI Agents with the Buzz Mobile App via QR Code",[429,5929,5930,5931,5934,5935,460],{},"The Buzz mobile app pairing only accepts the HTTPS protocol and the ",[494,5932,5933],{},"buzz-pair-relay"," is not started by default on ",[440,5936,2655],{},[919,5938,5940],{"className":1027,"code":5939,"language":1029,"meta":424,"style":424},"cd ~\u002Fbuzz\ncargo install --path crates\u002Fbuzz-pair-relay\n",[494,5941,5942,5948],{"__ignoreMap":424},[927,5943,5944,5946],{"class":929,"line":930},[927,5945,2775],{"class":958},[927,5947,5389],{"class":1040},[927,5949,5950,5952,5954,5956],{"class":929,"line":1056},[927,5951,5394],{"class":1036},[927,5953,4452],{"class":1040},[927,5955,5399],{"class":1040},[927,5957,5958],{"class":1040}," crates\u002Fbuzz-pair-relay\n",[429,5960,5961,5962,5965,5966,5968],{},"Add the following to ",[494,5963,5964],{},"compose.yml"," to start the ",[494,5967,5933],{}," service:",[919,5970,5972],{"className":1316,"code":5971,"language":1318,"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",[494,5973,5974,5981,5990,6010,6016,6026,6032,6043,6051,6057],{"__ignoreMap":424},[927,5975,5976,5979],{"class":929,"line":930},[927,5977,5978],{"class":1328},"  pair",[927,5980,1342],{"class":941},[927,5982,5983,5985,5987],{"class":929,"line":1056},[927,5984,3220],{"class":1328},[927,5986,1253],{"class":941},[927,5988,5989],{"class":1040}," ${BUZZ_IMAGE:-ghcr.io\u002Fblock\u002Fbuzz:main}\n",[927,5991,5992,5995,5997,6000,6002,6005,6007],{"class":929,"line":1063},[927,5993,5994],{"class":1328},"    entrypoint",[927,5996,1253],{"class":941},[927,5998,5999],{"class":941}," [",[927,6001,3650],{"class":941},[927,6003,6004],{"class":1040},"\u002Fusr\u002Flocal\u002Fbin\u002Fbuzz-pair-relay",[927,6006,3650],{"class":941},[927,6008,6009],{"class":941},"]\n",[927,6011,6012,6014],{"class":929,"line":1070},[927,6013,3250],{"class":1328},[927,6015,1342],{"class":941},[927,6017,6018,6021,6023],{"class":929,"line":1891},[927,6019,6020],{"class":1328},"      BUZZ_PAIR_RELAY_BIND_ADDR",[927,6022,1253],{"class":941},[927,6024,6025],{"class":1040}," 0.0.0.0:5000\n",[927,6027,6028,6030],{"class":929,"line":1896},[927,6029,3230],{"class":1328},[927,6031,1342],{"class":941},[927,6033,6034,6036,6038,6041],{"class":929,"line":1902},[927,6035,3237],{"class":941},[927,6037,3240],{"class":941},[927,6039,6040],{"class":1040},"${BUZZ_PAIR_RELAY_PORT:-5000}:5000",[927,6042,1923],{"class":941},[927,6044,6045,6047,6049],{"class":929,"line":2238},[927,6046,3312],{"class":1328},[927,6048,1253],{"class":941},[927,6050,3317],{"class":1040},[927,6052,6053,6055],{"class":929,"line":1667},[927,6054,4994],{"class":1328},[927,6056,1342],{"class":941},[927,6058,6059,6062,6065],{"class":929,"line":2344},[927,6060,6061],{"class":941},"      [",[927,6063,6064],{"class":1040},"buzz-net",[927,6066,6009],{"class":941},[429,6068,3149,6069,574,6072,4697,6075,2167],{},[494,6070,6071],{},"BUZZ_PAIRING_RELAY_URL",[494,6073,6074],{},"BUZZ_PAIR_RELAY_PORT",[494,6076,2805],{},[919,6078,6081],{"className":6079,"code":6080,"language":4598},[4596],"BUZZ_PAIRING_RELAY_URL=wss:\u002F\u002Fbuzz.pafor.me\u002Fpair\nBUZZ_PAIR_RELAY_PORT=5000\n",[494,6082,6080],{"__ignoreMap":424},[429,6084,6085,6086,6089],{},"Head to the '",[440,6087,6088],{},"Mobile","' in the Buzz desktop Settings:",[429,6091,6092],{},[432,6093],{"alt":6094,"src":6095},"Settings dialog in Buzz app showing the Mobile devices configuration tab","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-settings-mobile-tab.webp",[429,6097,6098],{},"Click \"Start pairing\" — a QR code is generated; scan this QR code with the Buzz app on the mobile device. It will be paired after you click \"Code Match\".",[429,6100,6101],{},[432,6102],{"alt":6103,"src":6104},"Generating secure pairing QR code in desktop client for Buzz mobile synchronization","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,6106,6107],{},"The agents on the Buzz mobile app are available only if they are running on the Buzz desktop app. The desktop machine has to be running for the agents to work.",[429,6109,6110],{},[432,6111],{"alt":6112,"src":6113},"Buzz mobile application interface showcasing synced active AI companion agents","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf-Hosting%20Buzz%20As%20The%20Workspace%20Where%20AI%20Agents%20Become%20Colleagues\u002Fbuzz-mobile-app-active-agents.webp",[473,6115,6117],{"id":6116},"final-thought","Final Thought",[429,6119,6120],{},"While Buzz is still too early for large scale production environments with several bugs and UI limitations, it is an exciting experience for small teams and solo developers. It offers a preview of what a collaborative, AI-first workspace truly feels like.",[473,6122,6124],{"id":6123},"reference","Reference",[484,6126,6127,6134,6141,6148],{},[487,6128,6129],{},[443,6130,6133],{"href":6131,"rel":6132},"https:\u002F\u002Fgithub.com\u002Fblock\u002Fbuzz",[447],"Buzz releases",[487,6135,6136],{},[443,6137,6140],{"href":6138,"rel":6139},"https:\u002F\u002Fblock.xyz\u002Finside\u002Fintroducing-buzz-where-humans-and-agents-work-together",[447],"Introducing Buzz",[487,6142,6143],{},[443,6144,6147],{"href":6145,"rel":6146},"https:\u002F\u002Fwww.hostinger.com\u002Ftutorials\u002Fwhat-is-buzz",[447],"What is buzz",[487,6149,6150],{},[443,6151,6154],{"href":6152,"rel":6153},"https:\u002F\u002Fmiget.com\u002Fblog\u002Fhow-to-self-host-buzz",[447],"How to self-host Buzz (Miget)",[1611,6156,6157],{},"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":1056,"depth":1063,"links":6159},[6160,6161,6162,6176,6185,6186,6187],{"id":4077,"depth":1056,"text":4078},{"id":4122,"depth":1056,"text":4123},{"id":4170,"depth":1056,"text":4171,"children":6163},[6164,6165,6169,6170,6171,6175],{"id":4174,"depth":1063,"text":4175},{"id":4200,"depth":1063,"text":4201,"children":6166},[6167,6168],{"id":4204,"depth":1070,"text":4205},{"id":4305,"depth":1070,"text":4306},{"id":4322,"depth":1063,"text":4323},{"id":4539,"depth":1063,"text":4540},{"id":4683,"depth":1063,"text":4684,"children":6172},[6173,6174],{"id":4687,"depth":1070,"text":4688},{"id":5071,"depth":1070,"text":5072},{"id":5134,"depth":1063,"text":5135},{"id":5174,"depth":1056,"text":5175,"children":6177},[6178,6179,6180],{"id":5252,"depth":1063,"text":5253},{"id":5297,"depth":1063,"text":5298},{"id":5334,"depth":1063,"text":5335,"children":6181},[6182,6183,6184],{"id":5357,"depth":1070,"text":5358},{"id":5600,"depth":1070,"text":5601},{"id":5673,"depth":1070,"text":5674},{"id":5926,"depth":1056,"text":5927},{"id":6116,"depth":1056,"text":6117},{"id":6123,"depth":1056,"text":6124},[1632,1631,1201],"2026-09-08",{"schemaOrg":6191,"robots":1665,"sitemap":6210},[6192,6193],{"@type":1642,"headline":382,"description":464,"image":465},{"@type":1644,"name":382,"description":464,"image":465,"step":6194},[6195,6198,6201,6204,6207],{"@type":1647,"name":6196,"text":6197},"Phase 1: Cloudflare Setup","Create a Cloudflare API Token and configure DNS settings.",{"@type":1647,"name":6199,"text":6200},"Phase 2: Install Docker","Set up and install Docker Engine on Ubuntu VPS.",{"@type":1647,"name":6202,"text":6203},"Phase 3: Clone and Configure","Clone the repository and configure compose variables.",{"@type":1647,"name":6205,"text":6206},"Phase 4: Caddy Integration","Build custom Caddy with Cloudflare DNS challenge module.",{"@type":1647,"name":6208,"text":6209},"Phase 5: Automated Backup","Configure a cron job to automatically back up PostgreSQL.",{"lastmod":6211},"2026-09-03",{"title":6213,"description":464,"ogTitle":382,"ogDescription":464,"twitterTitle":382,"twitterDescription":464},"How to Self-Host Block's Buzz Relay on Ubuntu VPS",[1671,6215,454,6216,6217],"Docker","Caddy","Cloudflare","ir8b59r6ypIp92KOOIJHFgPU_UhHH0zic0M1up4soME",{"id":6220,"title":378,"author":1673,"body":6221,"category":8085,"date":8087,"description":8088,"extension":1636,"image":8089,"imageAlt":8090,"isPublished":1059,"meta":8091,"minRead":4529,"navigation":1059,"path":51,"seo":8097,"stem":380,"tags":8098,"updatedAt":6211,"__hash__":8100},"article\u002Fen\u002Farticle\u002Fself-hosted-travel-planner-trek.md",{"type":426,"value":6222,"toc":8044},[6223,6226,6229,6232,6236,6240,6382,6386,6392,6411,6414,6418,6522,6533,6536,6541,6544,6555,6559,6563,6566,6569,6602,6606,6609,6641,6644,6684,6687,6692,6703,6707,6714,6718,6721,6815,6819,6825,6829,6836,6840,6843,6861,6871,6875,6878,6888,6892,6896,6905,6909,6913,6916,6920,6924,6927,6932,6935,6940,6946,6950,6954,6957,6961,6974,6979,6985,6990,6994,6997,7002,7007,7010,7017,7021,7024,7027,7037,7044,7049,7055,7060,7064,7069,7074,7077,7082,7086,7092,7096,7101,7105,7108,7111,7116,7121,7126,7130,7137,7142,7147,7152,7157,7161,7166,7171,7177,7181,7184,7188,7194,7199,7204,7210,7215,7220,7225,7237,7241,7246,7266,7271,7274,7278,7281,7286,7289,7336,7340,7347,7353,7358,7364,7369,7375,7380,7386,7389,7394,7401,7406,7412,7416,7422,7427,7432,7436,7440,7443,7447,7450,7457,7461,7468,7472,7483,7485,7489,7493,7503,7513,7518,7525,7530,7537,7541,7544,7708,7714,7718,7721,7726,7729,7735,7739,7746,7750,7753,7758,7765,7770,7774,7784,7855,7870,7873,7878,7882,7886,7896,7972,7982,7985,7989,7993,7996,8000,8003,8006,8015,8018,8041],[429,6224,6225],{},"The tedious part of travel planning is that flight booking PDFs, hotel confirmations, conversations with travel companions, and lists of places to visit are scattered in different locations. When it is time to work out total spending and split the bills, huge effort is needed to scroll through all that travel data.",[429,6227,6228],{},"TREK is an open-source travel planner that can be self-hosted, packing your itinerary, bookings, budget, and packing lists all into one place. The built-in MCP server enables AI agents (such as Claude Desktop) to directly manipulate travel data.",[429,6230,6231],{},"This guide will walk you through everything from deployment to fully managing a real trip from start to finish.",[874,6233,6235],{"id":6234},"_1-how-to-deploy-trek-travel-planner-using-docker","1. How to Deploy TREK Travel Planner Using Docker",[2125,6237,6239],{"id":6238},"install-docker-on-the-ubuntu-vps","Install Docker on the Ubuntu VPS",[919,6241,6243],{"className":1027,"code":6242,"language":1029,"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",[494,6244,6245,6249,6269,6273,6277,6309,6313,6317,6325,6329,6333,6349,6353,6357,6363,6367,6372],{"__ignoreMap":424},[927,6246,6247],{"class":929,"line":930},[927,6248,4336],{"class":1066},[927,6250,6251,6253,6255,6257,6259,6261,6263,6265,6267],{"class":929,"line":1056},[927,6252,2950],{"class":1036},[927,6254,4343],{"class":1040},[927,6256,4346],{"class":1040},[927,6258,4349],{"class":941},[927,6260,4352],{"class":1036},[927,6262,4355],{"class":1040},[927,6264,4358],{"class":1040},[927,6266,4361],{"class":1040},[927,6268,4364],{"class":1040},[927,6270,6271],{"class":929,"line":1063},[927,6272,1060],{"emptyLinePlaceholder":1059},[927,6274,6275],{"class":929,"line":1070},[927,6276,4373],{"class":1066},[927,6278,6279,6281,6283,6285,6287,6289,6291,6293,6295,6297,6299,6301,6303,6305,6307],{"class":929,"line":1891},[927,6280,4378],{"class":958},[927,6282,3240],{"class":941},[927,6284,4383],{"class":1040},[927,6286,4386],{"class":941},[927,6288,4389],{"class":1036},[927,6290,4392],{"class":1040},[927,6292,4395],{"class":941},[927,6294,4398],{"class":1040},[927,6296,3650],{"class":941},[927,6298,4349],{"class":941},[927,6300,4352],{"class":1036},[927,6302,3773],{"class":1040},[927,6304,4409],{"class":1040},[927,6306,4412],{"class":941},[927,6308,4415],{"class":1040},[927,6310,6311],{"class":929,"line":1896},[927,6312,1060],{"emptyLinePlaceholder":1059},[927,6314,6315],{"class":929,"line":1902},[927,6316,4424],{"class":1066},[927,6318,6319,6321,6323],{"class":929,"line":2238},[927,6320,1859],{"class":1036},[927,6322,4431],{"class":1040},[927,6324,4434],{"class":1040},[927,6326,6327],{"class":929,"line":1667},[927,6328,1060],{"emptyLinePlaceholder":1059},[927,6330,6331],{"class":929,"line":2344},[927,6332,4443],{"class":1066},[927,6334,6335,6337,6339,6341,6343,6345,6347],{"class":929,"line":2350},[927,6336,1859],{"class":1036},[927,6338,4431],{"class":1040},[927,6340,4452],{"class":1040},[927,6342,4455],{"class":1040},[927,6344,4458],{"class":1040},[927,6346,4461],{"class":1040},[927,6348,4464],{"class":1040},[927,6350,6351],{"class":929,"line":2356},[927,6352,1060],{"emptyLinePlaceholder":1059},[927,6354,6355],{"class":929,"line":2361},[927,6356,4493],{"class":1066},[927,6358,6359,6361],{"class":929,"line":2367},[927,6360,1148],{"class":1036},[927,6362,3573],{"class":1040},[927,6364,6365],{"class":929,"line":3309},[927,6366,1060],{"emptyLinePlaceholder":1059},[927,6368,6369],{"class":929,"line":3320},[927,6370,6371],{"class":1066},"# Starts automatically when your system boots\n",[927,6373,6374,6376,6378,6380],{"class":929,"line":3325},[927,6375,1859],{"class":1036},[927,6377,1862],{"class":1040},[927,6379,1989],{"class":1040},[927,6381,4484],{"class":1040},[2125,6383,6385],{"id":6384},"generate-the-encryption-key","Generate the encryption key",[429,6387,6388,6389,6391],{},"TREK uses a key to encrypt sensitive data. Use the following command or this ",[443,6390,4624],{"href":2826}," to generate the encryption key:",[919,6393,6395],{"className":1027,"code":6394,"language":1029,"meta":424,"style":424},"openssl rand -hex 32\n",[494,6396,6397],{"__ignoreMap":424},[927,6398,6399,6402,6405,6408],{"class":929,"line":930},[927,6400,6401],{"class":1036},"openssl",[927,6403,6404],{"class":1040}," rand",[927,6406,6407],{"class":1040}," -hex",[927,6409,6410],{"class":2919}," 32\n",[429,6412,6413],{},"Save it somewhere safe; losing it means losing access to encrypted data.",[2125,6415,6417],{"id":6416},"start-the-container","Start the container",[919,6419,6421],{"className":1027,"code":6420,"language":1029,"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",[494,6422,6423,6435,6445,6455,6472,6488,6498,6507,6517],{"__ignoreMap":424},[927,6424,6425,6427,6429,6432],{"class":929,"line":930},[927,6426,1148],{"class":1036},[927,6428,5455],{"class":1040},[927,6430,6431],{"class":1040}," -d",[927,6433,6434],{"class":937}," \\\n",[927,6436,6437,6440,6443],{"class":929,"line":1056},[927,6438,6439],{"class":1040},"  --name",[927,6441,6442],{"class":1040}," trek",[927,6444,6434],{"class":937},[927,6446,6447,6450,6453],{"class":929,"line":1063},[927,6448,6449],{"class":1040},"  -p",[927,6451,6452],{"class":1040}," 3000:3000",[927,6454,6434],{"class":937},[927,6456,6457,6460,6463,6465,6468,6470],{"class":929,"line":1070},[927,6458,6459],{"class":1040},"  -e",[927,6461,6462],{"class":1040}," ENCRYPTION_KEY=",[927,6464,3650],{"class":941},[927,6466,6467],{"class":1040},"\u003Cgenerated_key>",[927,6469,3650],{"class":941},[927,6471,6434],{"class":937},[927,6473,6474,6476,6479,6481,6484,6486],{"class":929,"line":1891},[927,6475,6459],{"class":1040},[927,6477,6478],{"class":1040}," APP_URL=",[927,6480,3650],{"class":941},[927,6482,6483],{"class":1040},"https:\u002F\u002Ftrek.pafor.me",[927,6485,3650],{"class":941},[927,6487,6434],{"class":937},[927,6489,6490,6493,6496],{"class":929,"line":1896},[927,6491,6492],{"class":1040},"  -v",[927,6494,6495],{"class":1040}," .\u002Fdata:\u002Fapp\u002Fdata",[927,6497,6434],{"class":937},[927,6499,6500,6502,6505],{"class":929,"line":1902},[927,6501,6492],{"class":1040},[927,6503,6504],{"class":1040}," .\u002Fuploads:\u002Fapp\u002Fuploads",[927,6506,6434],{"class":937},[927,6508,6509,6512,6515],{"class":929,"line":2238},[927,6510,6511],{"class":1040},"  --restart",[927,6513,6514],{"class":1040}," unless-stopped",[927,6516,6434],{"class":937},[927,6518,6519],{"class":929,"line":1667},[927,6520,6521],{"class":1040},"  mauriceboe\u002Ftrek:latest\n",[484,6523,6524],{},[487,6525,6526,6532],{},[440,6527,6528,6531],{},[494,6529,6530],{},"APP_URL"," must be set correctly"," — the MCP server's OAuth discovery flow depends on it. Set it to your final public HTTPS address from the start.",[429,6534,6535],{},"The first run takes a while to pull the image:",[432,6537],{"src":6538,"alt":6539,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-docker-pull-image.webp","Docker pull and run logs for TREK","max-width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,6542,6543],{},"Verify it's running:",[919,6545,6547],{"className":1027,"code":6546,"language":1029,"meta":424,"style":424},"docker ps\n",[494,6548,6549],{"__ignoreMap":424},[927,6550,6551,6553],{"class":929,"line":930},[927,6552,1148],{"class":1036},[927,6554,5115],{"class":1040},[432,6556],{"src":6557,"alt":6558,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-docker-ps-status.webp","Verifying running container status via docker ps",[874,6560,6562],{"id":6561},"_2-setting-up-domain-routing-ssl-with-caddy-reverse-proxy","2. Setting Up Domain Routing & SSL with Caddy Reverse Proxy",[429,6564,6565],{},"HTTPS is required for passkeys, and OAuth for MCP. The domain name is hosted on Cloudflare which comes with free SSL certificate and DDoS protection.",[429,6567,6568],{},"Caddy is set up as the secure reverse server to point to point 3000. An example of Caddyfile as follow:",[919,6570,6572],{"className":2865,"code":6571,"language":2867,"meta":424,"style":424},"{$TREK_DOMAIN} {\n  encode zstd gzip\n  reverse_proxy host.docker.internal:3000\n}\n",[494,6573,6574,6585,6589,6598],{"__ignoreMap":424},[927,6575,6576,6578,6581,6583],{"class":929,"line":930},[927,6577,2895],{"class":941},[927,6579,6580],{"class":937},"$TREK_DOMAIN",[927,6582,2901],{"class":941},[927,6584,2904],{"class":941},[927,6586,6587],{"class":929,"line":1056},[927,6588,2909],{"class":937},[927,6590,6591,6593,6595],{"class":929,"line":1063},[927,6592,2914],{"class":937},[927,6594,1253],{"class":941},[927,6596,6597],{"class":2919},"3000\n",[927,6599,6600],{"class":929,"line":1070},[927,6601,2882],{"class":941},[874,6603,6605],{"id":6604},"_3-initial-configuration-secure-admin-setup","3. Initial Configuration & Secure Admin Setup",[429,6607,6608],{},"There are two ways of creating the admin account:",[484,6610,6611,6622],{},[487,6612,6613,6621],{},[440,6614,6615,574,6618],{},[494,6616,6617],{},"ADMIN_EMAIL",[494,6619,6620],{},"ADMIN_PASSWORD"," are set as environment variables; those values are used directly.",[487,6623,6624,6625,6628,6629,6632,6633,6636,6637,6640],{},"TREK creates email ",[494,6626,6627],{},"admin@trek.local",", username ",[494,6630,6631],{},"admin",", and a ",[440,6634,6635],{},"randomly generated password printed to the container log",". Run ",[494,6638,6639],{},"docker logs trek"," to retrieve it.",[429,6642,6643],{},"If the password can't be found from the log, reset it:",[919,6645,6647],{"className":1027,"code":6646,"language":1029,"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",[494,6648,6649],{"__ignoreMap":424},[927,6650,6651,6653,6655,6658,6661,6664,6666,6669,6671,6674,6676,6678,6681],{"class":929,"line":930},[927,6652,1148],{"class":1036},[927,6654,1154],{"class":1040},[927,6656,6657],{"class":1040}," -it",[927,6659,6660],{"class":1040}," -e",[927,6662,6663],{"class":1040}," RESET_ADMIN_EMAIL=admin@trek.local",[927,6665,6660],{"class":1040},[927,6667,6668],{"class":1040}," RESET_ADMIN_PASSWORD=",[927,6670,5415],{"class":941},[927,6672,6673],{"class":1040},"YourNewPassword",[927,6675,5415],{"class":941},[927,6677,6442],{"class":1040},[927,6679,6680],{"class":1040}," node",[927,6682,6683],{"class":1040}," server\u002Freset-admin.js\n",[429,6685,6686],{},"You will be prompted to change the password on first login.",[432,6688],{"src":6689,"alt":6690,"style":6691},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-initial-login-password-prompt.webp","Initial login and admin password reset prompt","max-width: 215px; width:100% height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,6693,4217,6694,6697,6698],{},[440,6695,6696],{},"Admin"," and update the email:",[432,6699],{"src":6700,"alt":6701,"style":6702},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-admin-email-update-panel.webp","Setting up custom email in TREK admin settings","max-width: 700px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[2125,6704,6706],{"id":6705},"_31-backups","3.1 Backups",[429,6708,6709,6710],{},"Configure the automatic backups with a retention policy in the admin panel:\n",[432,6711],{"src":6712,"alt":6713,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-admin-backup-retention-policy.webp","Configuring automated backup schedules and retention rules",[2125,6715,6717],{"id":6716},"_32-store-uploaded-files-to-cloudflare-r2","3.2 Store Uploaded Files to Cloudflare R2",[429,6719,6720],{},"Storing uploaded files, photos, and backups in Cloudflare R2 keeps the VPS disk clean and light. TREK supports S3-compatible backends, and Cloudflare R2 fits this perfectly.",[532,6722,6723,6729,6742,6752,6763,6778,6789,6804],{},[487,6724,6725,6726,460],{},"Create an R2 bucket called ",[494,6727,6728],{},"trek",[487,6730,6731,6732,6735,6736,6737],{},"In the ",[440,6733,6734],{},"Account Details"," section, find your account ID:","\n  ",[432,6738],{"src":6739,"alt":6740,"style":6741},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fcloudflare-r2-account-details-id.webp","Locating Cloudflare account ID in portal","max-width: 325px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[487,6743,4231,6744,1253,6736,6747],{},[440,6745,6746],{},"Manage API Tokens",[432,6748],{"src":6749,"alt":6750,"style":6751},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fcloudflare-r2-manage-api-tokens-button.webp","Cloudflare portal Manage API Tokens screen","max-width: 282px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[487,6753,4231,6754,6757,6736,6758],{},[440,6755,6756],{},"Create Account API token"," with read\u002Fwrite permissions for the bucket:",[432,6759],{"src":6760,"alt":6761,"style":6762},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fcloudflare-r2-create-token-permissions.webp","Creating R2 access token with read and write permissions","max-width: 360px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[487,6764,4231,6765,6768,6769,6772,6736,6773],{},[440,6766,6767],{},"Storage"," on ",[440,6770,6771],{},"ADMINISTRATION"," panel:",[432,6774],{"src":6775,"alt":6776,"style":6777},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-administration-storage-menu.webp","Navigating to storage settings in TREK control panel","max-width: 539px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[487,6779,4231,6780,6783,6736,6784],{},[440,6781,6782],{},"Add Backend"," button and fill in the endpoint, bucket, and credentials:",[432,6785],{"src":6786,"alt":6787,"style":6788},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-add-storage-backend-credentials.webp","Configuring S3 compatible Cloudflare R2 storage backend","max-width: 445px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[487,6790,4231,6791,6794,6795,6798,6736,6799],{},[440,6792,6793],{},"Apply",", then the ",[440,6796,6797],{},"Test"," link button. You want to see \"Connection OK\":",[432,6800],{"src":6801,"alt":6802,"style":6803},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-test-storage-backend-connection-ok.webp","Successful storage connection test showing Connection OK","max-width: 677px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[487,6805,6806,6807,1253,6736,6810],{},"Switch all storage categories to Cloudflare R2 and click ",[440,6808,6809],{},"Save changes",[432,6811],{"src":6812,"alt":6813,"style":6814},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-switch-storage-categories-r2.webp","Routing all file storage categories to Cloudflare R2","max-width: 653px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[2125,6816,6818],{"id":6817},"_33-passkey-login","3.3 Passkey Login",[429,6820,6821,6822,1253],{},"TREK supports passkeys, two-factor authentication, and OIDC single sign-on. For passkeys, enter your domain name and allowed origins in settings, then click ",[440,6823,6824],{},"Save",[432,6826],{"src":6827,"alt":6828,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-passkey-allowed-origins-settings.webp","Registering allowed origins for secure Passkey authentication",[429,6830,6831,6832,6835],{},"Without the ",[440,6833,6834],{},"allowed origins"," configured, passkey registration will fail.",[2125,6837,6839],{"id":6838},"_34-google-maps-api-key","3.4 Google Maps API Key",[429,6841,6842],{},"A Google Maps key enriches place search with ratings, opening hours, and photos. TREK automatically falls back to OpenStreetMap with no key required, just without ratings and photos.",[429,6844,6845,6846,6851,6852,6855,6856],{},"Follow this ",[443,6847,6850],{"href":6848,"rel":6849},"https:\u002F\u002Fmapsplatform.google.com\u002Fmaps-demo-key\u002F",[447],"link"," and click ",[440,6853,6854],{},"Get demo key"," to request one:                                                  ",[432,6857],{"src":6858,"alt":6859,"style":6860},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fgoogle-maps-get-demo-api-key.webp","Requesting Google Maps Platform API key","max-width: 176px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,6862,6863,6864,6866,6867],{},"Paste the key in settings and click ",[440,6865,6797],{}," to confirm the connection:\n",[432,6868],{"src":6869,"alt":6870,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-google-maps-key-test-connection.webp","Verifying Google Maps API key connectivity in settings",[2125,6872,6874],{"id":6873},"_35-ai-integration","3.5 AI Integration",[429,6876,6877],{},"The AI model is used to parse booking confirmation emails and PDFs into structured reservations.",[429,6879,4231,6880,6883,6884,6887],{},[440,6881,6882],{},"Addons"," in the left menu and enable ",[440,6885,6886],{},"AI Parsing",". Select \"OpenAI\" (or another compatible provider) and fill in the provider details:",[432,6889],{"src":6890,"alt":6891,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-addons-enable-ai-parsing-openai.webp","Enabling AI Parsing addon with OpenAI integration",[2125,6893,6895],{"id":6894},"_36-mcp-access","3.6 MCP Access",[429,6897,6898,6899,6901,6902,1253],{},"Under ",[440,6900,6882],{},", enable ",[440,6903,6904],{},"MCP",[432,6906],{"src":6907,"alt":6908,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-addons-enable-mcp.webp","Activating Model Context Protocol MCP server addon",[2125,6910,6912],{"id":6911},"_37-plugins","3.7 Plugins",[429,6914,6915],{},"The following plugins are recommended and worth activating:",[432,6917],{"src":6918,"alt":6919,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-recommended-addons-plugins-activation.webp","List of active recommended plugins and addons",[2125,6921,6923],{"id":6922},"_38-create-your-everyday-user","3.8 Create Your Everyday User",[429,6925,6926],{},"Plan trips as a normal user, not as an admin. Create a regular user and log in with it:",[432,6928],{"src":6929,"alt":6930,"style":6931},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-create-regular-user-form.webp","Creating a regular user account in TREK panel","max-width: 420px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,6933,6934],{},"Once logged in, add a passkey or set up 2FA to harden the account:",[432,6936],{"src":6937,"alt":6938,"style":6939},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-user-security-passkey-2fa-setup.webp","Configuring user security settings with Passkeys and 2FA","max-width: 381px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,6941,4231,6942,6945],{},[440,6943,6944],{},"+ Add a passkey",", enter the current password, and confirm:",[432,6947],{"src":6948,"alt":6949,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-add-passkey-confirm-password.webp","Confirming password to register new hardware Passkey",[874,6951,6953],{"id":6952},"_4-testing-your-deployment-importing-historical-travel-data","4. Testing Your Deployment: Importing Historical Travel Data",[429,6955,6956],{},"A good way to learn TREK is to build up your travel history.",[2125,6958,6960],{"id":6959},"_41-create-the-trip","4.1 Create the trip",[429,6962,4231,6963,6966,6967,574,6970,6973],{},[440,6964,6965],{},"+ New Trip"," and set the ",[440,6968,6969],{},"Start Date",[440,6971,6972],{},"End Date"," to the past dates of the trip:",[432,6975],{"src":6976,"alt":6977,"style":6978},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-create-new-trip-details.webp","Creating a new trip with custom date ranges","max-width: 334px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,6980,6981,6982,1253],{},"Add a cover image (drag one in, or paste from the clipboard) and click ",[440,6983,6984],{},"Create New Trip",[432,6986],{"src":6987,"alt":6988,"style":6989},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-cover-image-upload.webp","Setting up high-quality trip cover image","max-width: 608px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[2125,6991,6993],{"id":6992},"_42-import-the-bookings","4.2 Import the bookings",[429,6995,6996],{},"Drop all the flight, train, and other transportation files in:",[432,6998],{"src":6999,"alt":7000,"style":7001},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-import-travel-booking-files.webp","Drag and drop area to import travel PDFs and bookings","max-width: 570px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[432,7003],{"src":7004,"alt":7005,"style":7006},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-import-booking-pdf-processing-status.webp","Uploaded reservation processing window showing extraction","max-width: 377px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7008,7009],{},"With AI model enabled, booking confirmation PDFs are parsed and extracted into structured reservations.",[429,7011,7012,7013,7016],{},"Review the parsed result and click ",[440,7014,7015],{},"Add"," to commit the booking detail:",[432,7018],{"src":7019,"alt":7020,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-review-parsed-booking-details.webp","Reviewing structured booking details extracted by AI",[429,7022,7023],{},"If a booking only exists in an email, export the email as a PDF and dump it in — the same extraction pipeline applies.",[429,7025,7026],{},"The following screenshots show how bookings are displayed:",[429,7028,7029,7033],{},[432,7030],{"src":7031,"alt":7032,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-bookings-timeline-view.webp","Comprehensive timeline display of travel bookings",[432,7034],{"src":7035,"alt":7036,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-booking-confirmation-details.webp","Detailed view of a confirmed transport reservation",[429,7038,7039,7040,7043],{},"On the ",[440,7041,7042],{},"Plan"," page, all the accommodations will be displayed on the map:",[432,7045],{"src":7046,"alt":7047,"style":7048},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-plan-accommodations-map-display.webp","Interactive map plotting all hotel accommodations","max-width: 546px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7050,4231,7051,7054],{},[440,7052,7053],{},"Atlas"," on the top menu bar for a list (and map) of every country you've visited:",[432,7056],{"src":7057,"alt":7058,"style":7059},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-atlas-countries-visited-summary.webp","Travel history overview in the personal Atlas tracker","max-width: 407px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[2125,7061,7063],{"id":7062},"_43-add-travel-companions","4.3 Add travel companions",[429,7065,3026,7066,2982],{},[440,7067,7068],{},"Share",[432,7070],{"src":7071,"alt":7072,"style":7073},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-share-options-button.webp","Opening the trip sharing dialog in TREK","max-width: 224px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7075,7076],{},"At the bottom of the dialog, guests can be added:",[432,7078],{"src":7079,"alt":7080,"style":7081},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-add-companions-guests.webp","Adding custom traveling companions and guests","max-width: 635px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[2125,7083,7085],{"id":7084},"_44-record-the-expenses","4.4 Record the expenses",[429,7087,4231,7088,7091],{},[440,7089,7090],{},"Add expense"," to add costs other than bookings such as health insurance, local transport, SIM cards:",[432,7093],{"src":7094,"alt":7095,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-add-custom-expense-form.webp","Inputting detailed spending data in expense form",[432,7097],{"src":7098,"alt":7099,"style":7100},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-expenses-list-billing-split.webp","Split bill breakdown and cost tracking ledger","max-width: 526px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[2125,7102,7104],{"id":7103},"_45-trip-segments","4.5 Trip segments",[429,7106,7107],{},"This feature requires the Trip Segment plugin to be installed.",[429,7109,7110],{},"Long trips break down into segments nicely, with each leg displaying its own bookings, places, and costs:",[432,7112],{"src":7113,"alt":7114,"style":7115},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-segments-overview-display.webp","Breaking down a complex itinerary into travel segments","max-width: 465px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[432,7117],{"src":7118,"alt":7119,"style":7120},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-segment-itinerary-details.webp","Active travel segment displaying places and schedules","max-width: 596px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[432,7122],{"src":7123,"alt":7124,"style":7125},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-trip-segments-interactive-map.webp","Mapping out distinct trip legs on the timeline","max-width: 605px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[2125,7127,7129],{"id":7128},"_46-create-a-journey-and-check-your-atlas","4.6 Create a journey and check your atlas",[429,7131,7132,7133,7136],{},"Group trips into a ",[440,7134,7135],{},"Journey"," and write stories to share the adventure with friends:",[432,7138],{"src":7139,"alt":7140,"style":7141},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-create-new-journey-group.webp","Consolidating multiple trips into a visual Journey","max-width: 441px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[432,7143],{"src":7144,"alt":7145,"style":7146},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-journey-timeline-story-writing.webp","Drafting visual stories in the Journey panel","max-width: 443px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[432,7148],{"src":7149,"alt":7150,"style":7151},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-journey-gallery-media-grid.webp","Media collection and gallery grid inside a Journey","max-width: 440px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[432,7153],{"src":7154,"alt":7155,"style":7156},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-journey-public-share-link.webp","Generating public share links for collaborative Journeys","max-width: 532px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[874,7158,7160],{"id":7159},"_5-designing-custom-itineraries-and-packing-lists","5. Designing Custom Itineraries and Packing Lists",[429,7162,4231,7163,7165],{},[440,7164,6965],{},", enter a name, and set the dates:",[432,7167],{"src":7168,"alt":7169,"style":7170},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-planning-new-trip-setup.webp","Initial prompt dialog to create an undated trip","max-width: 432px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7172,7173,7176],{},[440,7174,7175],{},"If you haven't fixed the dates yet, leave both empty."," A \"number of days\" field appears (up to 365). Plan first, schedule later.",[2125,7178,7180],{"id":7179},"_51-adding-places","5.1 Adding places",[429,7182,7183],{},"This is the most time-consuming step of any trip planning, and TREK has a couple of ways of doing it:",[432,7185],{"src":7186,"alt":7187,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-add-places-methods-overview.webp","Multi-channel methods to add new places to itineraries",[429,7189,7190,7193],{},[440,7191,7192],{},"1. Right-click the map"," to create a place at that exact location — the address is reverse-geocoded automatically:",[432,7195],{"src":7196,"alt":7197,"style":7198},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-right-click-map-location.webp","Right-clicking the map interface to pinpoint locations","max-width: 632px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[432,7200],{"src":7201,"alt":7202,"style":7203},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-right-click-reverse-geocode-address.webp","Automatic reverse-geocoding of selected map coords","max-width: 628px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7205,7206,7209],{},[440,7207,7208],{},"2. Click + Add Place\u002FActivity"," and search by name",[432,7211],{"src":7212,"alt":7213,"style":7214},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-search-place-by-name-input.webp","Searching for real-world places using text inputs","max-width: 642px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[432,7216],{"src":7217,"alt":7218,"style":7219},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-select-place-search-results-list.webp","Displaying place search results with address overlays","max-width: 594px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[432,7221],{"src":7222,"alt":7223,"style":7224},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-place-details-rich-info-card.webp","Comprehensive place info card with reviews and ratings","max-width: 568px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7226,7227,509,7230,5437,7233,7236],{},[440,7228,7229],{},"3. Paste a Google Maps URL",[494,7231,7232],{},"maps.app.goo.gl\u002F…",[494,7234,7235],{},"maps.google.com\u002F…",") into the search field. TREK parses out the name, address, and coordinates:",[432,7238],{"src":7239,"alt":7240,"style":6803},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-paste-google-maps-share-link.webp","Parsing locations directly from pasted Google Maps share links",[432,7242],{"src":7243,"alt":7244,"style":7245},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-google-maps-parsed-location.webp","Successful coordinate extraction from maps URL","max-width: 543px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7247,7248,7251,7252,509,7255,574,7258,7261,7262,7265],{},[440,7249,7250],{},"4. Bulk import"," — the easiest of all. If you already maintain a \"want to go\" list on Google Maps, export it as ",[494,7253,7254],{},".gpx",[494,7256,7257],{},".kml",[494,7259,7260],{},".kmz"," also work) and click ",[440,7263,7264],{},"Import file"," on the right panel to pull everything in at once:",[432,7267],{"src":7268,"alt":7269,"style":7270},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-bulk-import-places-gpx-file.webp","Performing bulk place imports using GPX or KML files","max-width: 389px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7272,7273],{},"Add everything interesting first, regardless of whether it fits the schedule. Allocate places to days later.",[2125,7275,7277],{"id":7276},"_52-day-plans-and-notes","5.2 Day plans and notes",[429,7279,7280],{},"The Day Plan organises places into days, in order. It's a collapsible list per day, and everything is drag-and-drop:",[432,7282],{"src":7283,"alt":7284,"style":7285},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-day-plan-drag-drop-ordering.webp","Customizing daily routes with drag-and-drop actions","max-width: 496px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7287,7288],{},"The details that make it useful:",[484,7290,7291,7301,7311,7321],{},[487,7292,7293,7296,7297],{},[440,7294,7295],{},"Transport between stops",": the bus icon at the top left of a day adds commuting transport (train, bus, flight legs within the day):\n",[432,7298],{"src":7299,"alt":7300,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-day-plan-commuting-transport-button.webp","Registering commuting transport between day segments",[487,7302,7303,7306,7307],{},[440,7304,7305],{},"Day notes",": the notes icon at the bottom left attaches icon-tagged notes — \"early start today\", \"this museum needs a reservation\":\n",[432,7308],{"src":7309,"alt":7310,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-day-plan-icon-tagged-notes-button.webp","Adding highly visible, icon-tagged custom notes to days",[487,7312,7313,7316,7317],{},[440,7314,7315],{},"Time slots",": drag a place from the right panel into a day, then assign it a time. Places with set times are auto connected on the map:\n",[432,7318],{"src":7319,"alt":7320,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-day-plan-timed-places-routing.webp","Auto-calculated transit routes between timed locations",[487,7322,7323,7324,7329,7330,574,7333,460],{},"Please refer to ",[443,7325,7328],{"href":7326,"rel":7327},"https:\u002F\u002Fgithub.com\u002Fliketrek\u002FTREK\u002Fwiki\u002FDay-Plans-and-Notes",[447],"Day Plans and Notes wiki page"," for ",[440,7331,7332],{},"Route optimisation",[440,7334,7335],{},"Weather",[2125,7337,7339],{"id":7338},"_53-collections-reusable-place-lists","5.3 Collections: reusable place lists",[429,7341,7342,7343,7346],{},"Collections allows the user to save a list of places outside of any trip. It can be shared with friends, and ready for the next trip. Places are ",[440,7344,7345],{},"copied"," into trips, so editing a trip entry never mutates your collection and vice versa.",[429,7348,4231,7349,7352],{},[440,7350,7351],{},"Collections"," in the top menu bar:",[432,7354],{"src":7355,"alt":7356,"style":7357},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-dashboard-view.webp","Accessing custom user collections for saved places","max-width: 495px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7359,4231,7360,7363],{},[440,7361,7362],{},"+ New list"," to create one:",[432,7365],{"src":7366,"alt":7367,"style":7368},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-create-new-list.webp","Creating custom lists in user collections","max-width: 269px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7370,4231,7371,7374],{},[440,7372,7373],{},"+ Add a place"," and fill in the details:",[432,7376],{"src":7377,"alt":7378,"style":7379},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-add-place-manually-form.webp","Manual form entry to populate custom collection lists","max-width: 271px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7381,7382,7385],{},[440,7383,7384],{},"Note:"," the search inside the \"Add a place\" dialog does not seem to work, so you will need to enter details manually.",[429,7387,7388],{},"If geo-coordinates of the places are available, the places show up on the map:",[432,7390],{"src":7391,"alt":7392,"style":7393},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-map-places-display.webp","Visualizing custom collection places on an interactive map","max-width: 592px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7395,7396,7397,7400],{},"To organise places with labels, click the ",[440,7398,7399],{},"tick-box"," icon:",[432,7402],{"src":7403,"alt":7404,"style":7405},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-select-places-tickbox.webp","Selection mode for bulk labeling of saved places","max-width: 662px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7407,7408,7409,1253],{},"Select the places to group, then click ",[440,7410,7411],{},"Assign label",[432,7413],{"src":7414,"alt":7415,"style":7245},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-group-assign-label.webp","Assigning descriptive labels to selected collection spots",[429,7417,4231,7418,7421],{},[440,7419,7420],{},"Manage labels"," to create labels first:",[432,7423],{"src":7424,"alt":7425,"style":7426},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-manage-custom-labels.webp","Creation and management of custom labels","max-width: 411px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7428,7429,7430,1253],{},"Select a label and click ",[440,7431,7411],{},[432,7433],{"src":7434,"alt":7435,"style":7059},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-collections-confirm-label-selection.webp","Applying custom labels to group places",[2125,7437,7439],{"id":7438},"_54-costs-and-budget","5.4 Costs and budget",[429,7441,7442],{},"We can add other expenses for the trip on the 'Costs' page.",[432,7444],{"src":7445,"alt":7446,"style":7285},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-costs-budget-overall-expenses-list.webp","Comprehensive expenses table and balance settling ledger",[429,7448,7449],{},"Payments made by travel companions can be added and split on the same page.",[429,7451,7452,7453,7456],{},"The settlement panel runs a greedy-matching algorithm to compute the ",[440,7454,7455],{},"minimum number of transfers"," for who owes whom, and how much.",[874,7458,7460],{"id":7459},"_6-leveraging-model-context-protocol-mcp-for-ai-powered-travel-planning","6. Leveraging Model Context Protocol (MCP) for AI-Powered Travel Planning",[429,7462,7463,7464,7467],{},"TREK has a built-in ",[440,7465,7466],{},"MCP (Model Context Protocol) server",", which lets AI agents read and write your travel data directly — over 150 tools and 30 resources covering trips, places, budgets, packing, bookings, and collaboration.",[2125,7469,7471],{"id":7470},"_61-cloudflare-zero-trust","6.1 Cloudflare Zero Trust",[429,7473,7474,7475,7477,7478,460],{},"Because TREK is running behind a ",[443,7476,1691],{"href":363}," network, you will need to add the domain to the split tunnels inclusion list. Otherwise, you will have issues with OAuth authorisation. Please refer to this GitHub issue: ",[443,7479,7482],{"href":7480,"rel":7481},"https:\u002F\u002Fgithub.com\u002Fliketrek\u002FTREK\u002Fissues\u002F1463",[447],"github issue",[462,7484],{"description":2571,"image":2572,"image-alt":2573,"label":2669,"min-read":2670,"title":362,"to":363},[432,7486],{"src":7487,"alt":7488,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fcloudflare-zero-trust-split-tunnels-domain.webp","Adding custom domains to Cloudflare Warp Split Tunnels",[2125,7490,7492],{"id":7491},"_62-claude-desktop","6.2 Claude Desktop",[429,7494,4231,7495,7498,7499],{},[440,7496,7497],{},"+ New Client"," to create an AI agent client:\n",[432,7500],{"src":7501,"alt":7502,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-register-new-mcp-client.webp","Registering a new custom client token in settings",[429,7504,7505,7506,7509,7510,1253],{},"Select the ",[440,7507,7508],{},"Claude Desktop"," tab and click ",[440,7511,7512],{},"Register Client",[432,7514],{"src":7515,"alt":7516,"style":7517},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-mcp-claude-desktop-client-credentials.webp","Generating Claude Desktop client credentials","max-width: 354px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7519,7520,7521,7524],{},"A client ID and client secret pair is displayed. Copy them somewhere safe. Then click ",[440,7522,7523],{},"Client Configuration"," to show the MCP config:",[432,7526],{"src":7527,"alt":7528,"style":7529},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-mcp-client-configuration-block.webp","Retrieving pre-formatted MCP server configuration block","max-width: 508px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7531,7532,7533,7536],{},"In Claude Desktop, click ",[440,7534,7535],{},"Edit Config"," to open the local MCP servers configuration file:",[432,7538],{"src":7539,"alt":7540,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fclaude-desktop-mcp-config-json.webp","Editing Claude Desktop local MCP config json file",[429,7542,7543],{},"Paste the TREK config, replacing the placeholders with your credentials:",[919,7545,7547],{"className":2865,"code":7546,"language":2867,"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",[494,7548,7549,7563,7576,7598,7612,7624,7635,7646,7691,7696,7701],{"__ignoreMap":424},[927,7550,7551,7554,7557,7559,7561],{"class":929,"line":930},[927,7552,7553],{"class":941},"  \"",[927,7555,7556],{"class":1040},"mcpServers",[927,7558,3650],{"class":941},[927,7560,578],{"class":937},[927,7562,2874],{"class":941},[927,7564,7565,7568,7570,7572,7574],{"class":929,"line":1056},[927,7566,7567],{"class":941},"    \"",[927,7569,6728],{"class":933},[927,7571,3650],{"class":941},[927,7573,1253],{"class":941},[927,7575,2904],{"class":941},[927,7577,7578,7581,7584,7586,7588,7590,7593,7595],{"class":929,"line":1063},[927,7579,7580],{"class":941},"      \"",[927,7582,7583],{"class":1036},"command",[927,7585,3650],{"class":941},[927,7587,1253],{"class":941},[927,7589,3240],{"class":941},[927,7591,7592],{"class":1040},"npx",[927,7594,3650],{"class":941},[927,7596,7597],{"class":941},",\n",[927,7599,7600,7602,7605,7607,7609],{"class":929,"line":1070},[927,7601,7580],{"class":941},[927,7603,7604],{"class":1036},"args",[927,7606,3650],{"class":941},[927,7608,1253],{"class":941},[927,7610,7611],{"class":941}," [\n",[927,7613,7614,7617,7620,7622],{"class":929,"line":1891},[927,7615,7616],{"class":941},"        \"",[927,7618,7619],{"class":1040},"mcp-remote",[927,7621,3650],{"class":941},[927,7623,7597],{"class":941},[927,7625,7626,7628,7631,7633],{"class":929,"line":1896},[927,7627,7616],{"class":941},[927,7629,7630],{"class":1040},"https:\u002F\u002Ftrek.pafor.me\u002Fmcp",[927,7632,3650],{"class":941},[927,7634,7597],{"class":941},[927,7636,7637,7639,7642,7644],{"class":929,"line":1902},[927,7638,7616],{"class":941},[927,7640,7641],{"class":1040},"--static-oauth-client-info",[927,7643,3650],{"class":941},[927,7645,7597],{"class":941},[927,7647,7648,7650,7652,7655,7658,7660,7662,7664,7667,7669,7671,7673,7676,7678,7680,7682,7685,7687,7689],{"class":929,"line":2238},[927,7649,7616],{"class":941},[927,7651,2895],{"class":1040},[927,7653,7654],{"class":937},"\\\"",[927,7656,7657],{"class":1040},"client_id",[927,7659,7654],{"class":937},[927,7661,578],{"class":1040},[927,7663,7654],{"class":937},[927,7665,7666],{"class":1040},"\u003Cyour_client_id>",[927,7668,7654],{"class":937},[927,7670,743],{"class":1040},[927,7672,7654],{"class":937},[927,7674,7675],{"class":1040},"client_secret",[927,7677,7654],{"class":937},[927,7679,578],{"class":1040},[927,7681,7654],{"class":937},[927,7683,7684],{"class":1040},"\u003Cyour_client_secret>",[927,7686,7654],{"class":937},[927,7688,2901],{"class":1040},[927,7690,1923],{"class":941},[927,7692,7693],{"class":929,"line":1667},[927,7694,7695],{"class":941},"      ]\n",[927,7697,7698],{"class":929,"line":2344},[927,7699,7700],{"class":941},"    }\n",[927,7702,7703,7706],{"class":929,"line":2350},[927,7704,7705],{"class":941},"  }",[927,7707,7597],{"class":937},[429,7709,7710,7711,1253],{},"Restart Claude Desktop, and the TREK server shows as connected under ",[440,7712,7713],{},"Local MCP servers",[432,7715],{"src":7716,"alt":7717,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fclaude-desktop-mcp-trek-server-connected.webp","Verifying active TREK connection status inside Claude UI",[429,7719,7720],{},"Now run a prompt:",[432,7722],{"src":7723,"alt":7724,"style":7725},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fclaude-desktop-mcp-natural-language-prompt.webp","Prompting Claude in natural language to manipulate travel data","max-width: 550px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7727,7728],{},"Let's add an expense in natural language:",[919,7730,7733],{"className":7731,"code":7732,"language":4598,"meta":424},[4596],"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",[494,7734,7732],{"__ignoreMap":424},[432,7736],{"src":7737,"alt":7738,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fclaude-desktop-mcp-add-expense-response.webp","Claude utilizing tools to automatically record an expense",[429,7740,7741,7742,7745],{},"Checking the ",[440,7743,7744],{},"Costs"," page, the expense is created with \"No one paid yet\", since no payer was mentioned:",[432,7747],{"src":7748,"alt":7749,"style":6702},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-costs-page-mcp-parsed-expense.webp","Confirming the newly parsed AI expense in the Costs view",[429,7751,7752],{},"Adding to the packing list works the same way:",[432,7754],{"src":7755,"alt":7756,"style":7757},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fclaude-desktop-mcp-add-packing-items.webp","Claude adding packing items using natural language prompts","max-width: 631px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7759,7760,7761,7764],{},"Refresh the ",[440,7762,7763],{},"Packing List"," page and the three items are there:",[432,7766],{"src":7767,"alt":7768,"style":7769},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Ftrek-packing-list-mcp-parsed-items.webp","Confirming newly parsed packing items on the Packing List page","max-width: 312px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[2125,7771,7773],{"id":7772},"_63-gemini-cli-dynamic-registration","6.3 Gemini CLI (dynamic registration)",[429,7775,7776,7777,7780,7781,1253],{},"Gemini CLI supports ",[440,7778,7779],{},"dynamic registration",", that is no pre-created client needed. Add this to ",[494,7782,7783],{},".gemini\u002Fsettings.json",[919,7785,7787],{"className":2865,"code":7786,"language":2867,"meta":424,"style":424},"    \"trek\": {\n      \"httpUrl\": \"https:\u002F\u002Ftrek.pafor.me\u002Fmcp\",\n      \"oauth\": {\n        \"enabled\": true\n      }\n    }\n",[494,7788,7789,7801,7820,7833,7846,7851],{"__ignoreMap":424},[927,7790,7791,7793,7795,7797,7799],{"class":929,"line":930},[927,7792,7567],{"class":941},[927,7794,6728],{"class":1040},[927,7796,3650],{"class":941},[927,7798,578],{"class":937},[927,7800,2874],{"class":941},[927,7802,7803,7805,7808,7810,7812,7814,7816,7818],{"class":929,"line":1056},[927,7804,7580],{"class":941},[927,7806,7807],{"class":933},"httpUrl",[927,7809,3650],{"class":941},[927,7811,1253],{"class":941},[927,7813,3240],{"class":941},[927,7815,7630],{"class":1040},[927,7817,3650],{"class":941},[927,7819,7597],{"class":941},[927,7821,7822,7824,7827,7829,7831],{"class":929,"line":1063},[927,7823,7580],{"class":941},[927,7825,7826],{"class":933},"oauth",[927,7828,3650],{"class":941},[927,7830,1253],{"class":941},[927,7832,2904],{"class":941},[927,7834,7835,7837,7840,7842,7844],{"class":929,"line":1070},[927,7836,7616],{"class":941},[927,7838,7839],{"class":1036},"enabled",[927,7841,3650],{"class":941},[927,7843,1253],{"class":941},[927,7845,1353],{"class":941},[927,7847,7848],{"class":929,"line":1891},[927,7849,7850],{"class":941},"      }\n",[927,7852,7853],{"class":929,"line":1896},[927,7854,7700],{"class":941},[429,7856,1798,7857,7860,7861,7864,7865],{},[494,7858,7859],{},"gemini"," in the terminal and click ",[440,7862,7863],{},"Approve"," when the authorisation prompt appears:\n",[432,7866],{"src":7867,"alt":7868,"style":7869},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fmcp-client-oauth-authorization-prompt.webp","Approving OAuth access for the TREK MCP server","max-width: 488px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7871,7872],{},"Then start with a simple prompt:",[432,7874],{"src":7875,"alt":7876,"style":7877},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fgemini-cli-mcp-prompt-itinerary.webp","Prompting Gemini CLI to fetch travel itineraries","max-width: 415px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[432,7879],{"src":7880,"alt":7881,"style":7151},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fgemini-cli-mcp-display-itinerary.webp","Gemini CLI successfully displaying structured trip information",[2125,7883,7885],{"id":7884},"_64-kimi-cli-dynamic-registration","6.4 Kimi CLI (dynamic registration)",[429,7887,7888,7889,3011,7892,7895],{},"Same approach — add to ",[494,7890,7891],{},"mcp.json",[494,7893,7894],{},"\u002FUsers\u002F\u003Cuser>\u002F.kimi\u002F"," folder:",[919,7897,7899],{"className":2865,"code":7898,"language":2867,"meta":424,"style":424},"    \"trek\": {\n      \"type\": \"http\",\n      \"url\": \"https:\u002F\u002Ftrek.pafor.me\u002Fmcp\",\n      \"auth\": \"oauth\"\n    }\n",[494,7900,7901,7913,7933,7951,7968],{"__ignoreMap":424},[927,7902,7903,7905,7907,7909,7911],{"class":929,"line":930},[927,7904,7567],{"class":941},[927,7906,6728],{"class":1040},[927,7908,3650],{"class":941},[927,7910,578],{"class":937},[927,7912,2874],{"class":941},[927,7914,7915,7917,7920,7922,7924,7926,7929,7931],{"class":929,"line":1056},[927,7916,7580],{"class":941},[927,7918,7919],{"class":933},"type",[927,7921,3650],{"class":941},[927,7923,1253],{"class":941},[927,7925,3240],{"class":941},[927,7927,7928],{"class":1040},"http",[927,7930,3650],{"class":941},[927,7932,7597],{"class":941},[927,7934,7935,7937,7939,7941,7943,7945,7947,7949],{"class":929,"line":1063},[927,7936,7580],{"class":941},[927,7938,858],{"class":933},[927,7940,3650],{"class":941},[927,7942,1253],{"class":941},[927,7944,3240],{"class":941},[927,7946,7630],{"class":1040},[927,7948,3650],{"class":941},[927,7950,7597],{"class":941},[927,7952,7953,7955,7958,7960,7962,7964,7966],{"class":929,"line":1070},[927,7954,7580],{"class":941},[927,7956,7957],{"class":933},"auth",[927,7959,3650],{"class":941},[927,7961,1253],{"class":941},[927,7963,3240],{"class":941},[927,7965,7826],{"class":1040},[927,7967,1923],{"class":941},[927,7969,7970],{"class":929,"line":1891},[927,7971,7700],{"class":941},[429,7973,1798,7974,7860,7977,1342,7979],{},[494,7975,7976],{},"kimi mcp auth trek",[440,7978,7863],{},[432,7980],{"src":7867,"alt":7868,"style":7981},"max-width: 453px; width: 100%; height: auto; border-radius: 8px; margin: 1.5rem auto; display: block;",[429,7983,7984],{},"Once authorised, the available tools are listed:",[432,7986],{"src":7987,"alt":7988,"style":6540},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002Fkimi-cli-mcp-authorized-tools-list.webp","Kimi CLI displaying available tools after successful authorization",[874,7990,7992],{"id":7991},"_7-mobile-experience","7. Mobile Experience",[429,7994,7995],{},"TREK is a PWA (progressive web app) on mobile devices. A service worker caches map tiles and API data, so your itinerary remains readable offline. However, push notifications may experience some latency compared to a native app.",[874,7997,7999],{"id":7998},"final-thoughts","Final Thoughts",[429,8001,8002],{},"Connecting AI agents through MCP saves a lot of the tedious work of entering flight and accommodation bookings. In addition, agents can suggest places of interest based on your travel dates and season. A single conversation with an AI agent can cover the entire pipeline, from research and itinerary building to budget tracking and packing.",[429,8004,8005],{},"There are some minor technical glitches. For instance, when importing bookings from PDFs, the currency defaults to the trip's base currency rather than the currency actually paid. Also, when creating a new list in Collections, any cover image added during creation disappears on save, though it can be manually added back when editing.",[429,8007,8008,8009,8014],{},"There is a slight technical barrier, as you need to host this on your own server. TREK is primarily designed for people who travel frequently and have high expectations of how they organise their travel data. We suggest trying the official demo at ",[443,8010,8013],{"href":8011,"rel":8012},"https:\u002F\u002Fdemo.liketrek.com\u002F",[447],"demo.liketrek.com"," before considering self-hosting.",[874,8016,8017],{"id":6123},"Reference:",[484,8019,8020,8027,8034],{},[487,8021,8022],{},[443,8023,8026],{"href":8024,"rel":8025},"https:\u002F\u002Fgithub.com\u002Fliketrek\u002FTREK\u002Fwiki\u002FQuick-Start",[447],"TREK Quick Start",[487,8028,8029],{},[443,8030,8033],{"href":8031,"rel":8032},"https:\u002F\u002Fgithub.com\u002Fliketrek\u002FTREK\u002Fwiki\u002FTroubleshooting",[447],"TREK Troubleshooting",[487,8035,8036],{},[443,8037,8040],{"href":8038,"rel":8039},"https:\u002F\u002Fgithub.com\u002Fliketrek\u002FTREK\u002Fwiki\u002FMCP-Scopes",[447],"TREK MCP Scopes",[1611,8042,8043],{},"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":1056,"depth":1063,"links":8045},[8046,8051,8052,8062,8070,8076,8082,8083,8084],{"id":6234,"depth":1063,"text":6235,"children":8047},[8048,8049,8050],{"id":6238,"depth":1070,"text":6239},{"id":6384,"depth":1070,"text":6385},{"id":6416,"depth":1070,"text":6417},{"id":6561,"depth":1063,"text":6562},{"id":6604,"depth":1063,"text":6605,"children":8053},[8054,8055,8056,8057,8058,8059,8060,8061],{"id":6705,"depth":1070,"text":6706},{"id":6716,"depth":1070,"text":6717},{"id":6817,"depth":1070,"text":6818},{"id":6838,"depth":1070,"text":6839},{"id":6873,"depth":1070,"text":6874},{"id":6894,"depth":1070,"text":6895},{"id":6911,"depth":1070,"text":6912},{"id":6922,"depth":1070,"text":6923},{"id":6952,"depth":1063,"text":6953,"children":8063},[8064,8065,8066,8067,8068,8069],{"id":6959,"depth":1070,"text":6960},{"id":6992,"depth":1070,"text":6993},{"id":7062,"depth":1070,"text":7063},{"id":7084,"depth":1070,"text":7085},{"id":7103,"depth":1070,"text":7104},{"id":7128,"depth":1070,"text":7129},{"id":7159,"depth":1063,"text":7160,"children":8071},[8072,8073,8074,8075],{"id":7179,"depth":1070,"text":7180},{"id":7276,"depth":1070,"text":7277},{"id":7338,"depth":1070,"text":7339},{"id":7438,"depth":1070,"text":7439},{"id":7459,"depth":1063,"text":7460,"children":8077},[8078,8079,8080,8081],{"id":7470,"depth":1070,"text":7471},{"id":7491,"depth":1070,"text":7492},{"id":7772,"depth":1070,"text":7773},{"id":7884,"depth":1070,"text":7885},{"id":7991,"depth":1063,"text":7992},{"id":7998,"depth":1063,"text":7999},{"id":6123,"depth":1063,"text":8017},[8086,1631],"travel","2026-09-01","Learn how to deploy TREK using Docker, secure it via Cloudflare R2 and Caddy, and leverage AI agents with MCP for seamless travel planning.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosted%20travel%20planner%20TREK\u002FEN-Self-hosted-travel-planner-TREK.webp","A premium minimalist 3D illustration of the TREK self-hosted travel planner dashboard on a warm parchment background.",{"schemaOrg":8092,"robots":1665,"sitemap":8096},[8093,8094],{"@type":1644,"headline":378,"description":8088},{"@type":4046,"headline":8095,"description":8088},"How to Self-Host TREK: The Ultimate AI Travel Planner",{"lastmod":8087},{"title":8095,"description":8088,"ogTitle":378,"ogDescription":8088,"twitterTitle":378,"twitterDescription":8088},[6215,8099,6216,6217,6904],"TREK","hV0BoKmT_W4ef-yv8Igqd32Dqqk7LsAlRAABPpfuoZ8",{"id":8102,"title":366,"author":424,"body":8103,"category":8653,"date":8654,"description":8655,"extension":1636,"image":8656,"imageAlt":8657,"isPublished":1059,"meta":8658,"minRead":1070,"navigation":1059,"path":45,"seo":8662,"stem":368,"tags":8664,"updatedAt":1673,"__hash__":8668},"article\u002Fen\u002Farticle\u002Fhow-ai-agent-skills-replace-nuxt-app-scaffolding-scripts.md",{"type":426,"value":8104,"toc":8646},[8105,8118,8122,8125,8221,8224,8252,8258,8262,8276,8293,8297,8308,8468,8472,8554,8558,8566,8586,8593,8608,8618,8621,8627,8630,8635,8643],[429,8106,8107,8108,574,8111,8114,8115,460],{},"When we start a new app using the Nuxt framework, we have to go through tedious steps like installing modules and setting up configurations such as ",[494,8109,8110],{},"nuxt.config.ts",[494,8112,8113],{},"wrangler.jsonc",". A script can solve this problem, but it hits its limits as variations increase. This is why we explored and replaced scripts with an ",[440,8116,8117],{},"agent skill",[473,8119,8121],{"id":8120},"what-traditional-shell-scripts-are-good-at","What Traditional Shell Scripts Are Good At",[429,8123,8124],{},"A script is good at executing a fixed set of instructions in sequence with hardcoded decisions.",[919,8126,8128],{"className":1027,"code":8127,"language":1029,"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",[494,8129,8130,8135,8142,8146,8185,8189,8199,8203,8212],{"__ignoreMap":424},[927,8131,8132],{"class":929,"line":930},[927,8133,8134],{"class":1066},"#!\u002Fusr\u002Fbin\u002Fenv bash\n",[927,8136,8137,8140],{"class":929,"line":1056},[927,8138,8139],{"class":958},"set",[927,8141,5159],{"class":1040},[927,8143,8144],{"class":929,"line":1063},[927,8145,1060],{"emptyLinePlaceholder":1059},[927,8147,8148,8150,8153,8156,8158,8162,8164,8167,8170,8173,8176,8179,8182],{"class":929,"line":1070},[927,8149,7592],{"class":1036},[927,8151,8152],{"class":1040}," nuxi@latest",[927,8154,8155],{"class":1040}," init",[927,8157,3240],{"class":941},[927,8159,8161],{"class":8160},"sHdIc","$1",[927,8163,3650],{"class":941},[927,8165,8166],{"class":1040}," --template",[927,8168,8169],{"class":1040}," minimal",[927,8171,8172],{"class":1040}," --packageManager",[927,8174,8175],{"class":1040}," pnpm",[927,8177,8178],{"class":1040}," --no-gitInit",[927,8180,8181],{"class":1040}," -M",[927,8183,8184],{"class":1040}," @nuxt\u002Fui,@nuxthub\u002Fcore,@vueuse\u002Fnuxt\n",[927,8186,8187],{"class":929,"line":1891},[927,8188,1060],{"emptyLinePlaceholder":1059},[927,8190,8191,8193,8195,8197],{"class":929,"line":1896},[927,8192,2775],{"class":958},[927,8194,3240],{"class":941},[927,8196,8161],{"class":8160},[927,8198,1923],{"class":941},[927,8200,8201],{"class":929,"line":1902},[927,8202,1060],{"emptyLinePlaceholder":1059},[927,8204,8205,8207,8210],{"class":929,"line":2238},[927,8206,2792],{"class":1036},[927,8208,8209],{"class":1040}," ~\u002Ftemplates\u002Fnuxt.config.ts",[927,8211,4855],{"class":1040},[927,8213,8214,8216,8219],{"class":929,"line":1667},[927,8215,2792],{"class":1036},[927,8217,8218],{"class":1040}," ~\u002Ftemplates\u002Fwrangler.jsonc",[927,8220,4855],{"class":1040},[429,8222,8223],{},"This script works until the following occurs:",[484,8225,8226,8232,8242],{},[487,8227,8228,8231],{},[440,8229,8230],{},"Fixed defaults."," The script hardcodes the Nuxt UI module; what if we want the Ant Design UI module? Every new module option requires another argument from the user.",[487,8233,8234,8237,8238,8241],{},[440,8235,8236],{},"It can't read the user's intent."," \"Build me a blog\" needs ",[494,8239,8240],{},"@nuxt\u002Fcontent","; \"build me a website with newsletters\" needs Cloudflare D1 + Drizzle. A script can't tell the difference—each variation needs a new script.",[487,8243,8244,8247,8248,8251],{},[440,8245,8246],{},"It goes stale silently."," Nuxt's conventions change between major versions. Nuxt 4 changed the source directory to ",[494,8249,8250],{},"app\u002F",". A script that is written for Nuxt 3 quietly scaffolds the wrong layout and never alerts the user.",[429,8253,8254,8257],{},[440,8255,8256],{},"App scaffolding"," is a decision issue, not an execution issue. The script will not scale when the number of decisions increases.",[473,8259,8261],{"id":8260},"why-use-an-ai-agent-skill-over-traditional-scripts","Why Use an AI Agent Skill Over Traditional Scripts?",[429,8263,8264,8265,8268,8269,8272,8273,8275],{},"An agent skill is not a set of code that executes, but a ",[440,8266,8267],{},"set of knowledge the AI agent follows",". It contains ",[494,8270,8271],{},"SKILL.md"," and can bundle any other files the task requires (such as reference documents, templates, and executable scripts). The article, ",[443,8274,350],{"href":351},", explains how an agent skill works. A skill maintains a script's diligence while adding the reasonable judgements that a script lacks:",[484,8277,8278,8281,8284,8287,8290],{},[487,8279,8280],{},"Infers the user's intention to determine whether the app needs a database.",[487,8282,8283],{},"Decides which optional modules are needed from the specified list. For example, Nuxt Content, i18n, and analytics are opt-in when requested by the user.",[487,8285,8286],{},"Adapts to the current ecosystem using the latest Nuxt framework, NuxtHub for Cloudflare bindings, and Wrangler for deployment.",[487,8288,8289],{},"Recovers when a step fails.",[487,8291,8292],{},"Verifies against a final checklist before handing the project over.",[473,8294,8296],{"id":8295},"behind-the-scenes-of-our-nuxt-cloudflare-scaffolding-skill","Behind the Scenes of Our Nuxt & Cloudflare Scaffolding Skill",[429,8298,8299,8300,8307],{},"The skill, ",[443,8301,8304],{"href":8302,"rel":8303},"https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fscaffold-nuxt-cloudflare-app-skill",[447],[494,8305,8306],{},"scaffold-nuxt-cloudflare-app-skill",", walks through a production-oriented scaffold:",[532,8309,8310,8341,8360,8384,8413,8448,8454],{},[487,8311,8312,8315,8316],{},[440,8313,8314],{},"Clarify anything"," that cannot be inferred:\n",[484,8317,8318,8329,8332],{},[487,8319,8320,8321,8324,8325,8328],{},"UI kit (",[440,8322,8323],{},"Nuxt UI"," by default or ",[440,8326,8327],{},"Antdv Next",");",[487,8330,8331],{},"Whether a database is required (such as Cloudflare D1);",[487,8333,8334,8335,5437,8338,8340],{},"Extra modules like ",[494,8336,8337],{},"@nuxtjs\u002Fi18n",[494,8339,8240],{}," for CMS features.",[487,8342,8343,759,8346,8349,8350,8352,8353,8356,8357,460],{},[440,8344,8345],{},"Scaffolds the base app",[494,8347,8348],{},"pnpm dlx nuxi@latest init"," for the latest version of the Nuxt framework with ",[494,8351,3541],{}," as the package manager. It then sets native-build allowlists so Cloudflare's build environment can compile ",[494,8354,8355],{},"better-sqlite3","\u002F",[494,8358,8359],{},"sharp",[487,8361,8362,578,8365,5437,8368,743,8371,743,8374,743,8377,743,8380,8383],{},[440,8363,8364],{},"Installs modules from a decision table",[494,8366,8367],{},"@nuxt\u002Fui",[494,8369,8370],{},"@antdv-next\u002Fnuxt",[494,8372,8373],{},"@nuxt\u002Fimage",[494,8375,8376],{},"@nuxtjs\u002Fseo",[494,8378,8379],{},"@nuxthub\u002Fcore",[494,8381,8382],{},"@vueuse\u002Fnuxt",", plus Drizzle\u002FD1, Nuxt Content, and i18n only when selected.",[487,8385,8386,1342,8389],{},[440,8387,8388],{},"Lays out the directory structure",[484,8390,8391,8395,8400,8405,8410],{},[487,8392,8393],{},[494,8394,8250],{},[487,8396,8397],{},[494,8398,8399],{},"server\u002F",[487,8401,8402],{},[494,8403,8404],{},"shared\u002F",[487,8406,8407],{},[494,8408,8409],{},"tests\u002F",[487,8411,8412],{},"root config files.",[487,8414,8415,1342,8420],{},[440,8416,8417,8418],{},"Configures ",[494,8419,8110],{},[484,8421,8422,8431,8438,8443],{},[487,8423,8424,8356,8427,8430],{},[494,8425,8426],{},"site.url",[494,8428,8429],{},"site.name"," for SEO",[487,8432,8433,8434,8437],{},"NuxtHub ",[494,8435,8436],{},"hub"," block for Cloudflare",[487,8439,8440],{},[494,8441,8442],{},"routeRules",[487,8444,8445],{},[494,8446,8447],{},"compatibilityDate",[487,8449,8450],{},[440,8451,8417,8452],{},[494,8453,8113],{},[487,8455,8456,8459,8460,8463,8464,8467],{},[440,8457,8458],{},"Sets up Vitest and ESLint",", then runs a ",[440,8461,8462],{},"final checklist"," including ",[494,8465,8466],{},"pnpm install && pnpm dev"," before considering the job done.",[473,8469,8471],{"id":8470},"shell-scripts-vs-ai-agent-skills-a-side-by-side-comparison","Shell Scripts vs AI Agent Skills: A Side-by-Side Comparison",[603,8473,8474,8486],{},[606,8475,8476],{},[609,8477,8478,8480,8483],{},[612,8479],{},[612,8481,8482],{},"Script",[612,8484,8485],{},"Skill",[632,8487,8488,8499,8510,8521,8532,8543],{},[609,8489,8490,8493,8496],{},[637,8491,8492],{},"User's intent",[637,8494,8495],{},"❌ fixed defaults",[637,8497,8498],{},"✅ adapts to the request",[609,8500,8501,8504,8507],{},[637,8502,8503],{},"Decision making",[637,8505,8506],{},"only if you pre-code flags",[637,8508,8509],{},"✅ judged at runtime",[609,8511,8512,8515,8518],{},[637,8513,8514],{},"Version changes",[637,8516,8517],{},"manual rewrite",[637,8519,8520],{},"✅ checks the current state",[609,8522,8523,8526,8529],{},[637,8524,8525],{},"Error recovery",[637,8527,8528],{},"halts",[637,8530,8531],{},"✅ fixes and continues",[609,8533,8534,8537,8540],{},[637,8535,8536],{},"Result verification",[637,8538,8539],{},"❌",[637,8541,8542],{},"✅ final checklist",[609,8544,8545,8548,8551],{},[637,8546,8547],{},"Maintenance cost",[637,8549,8550],{},"flags sprawl, version bumps",[637,8552,8553],{},"editing Markdown, not code",[473,8555,8557],{"id":8556},"how-to-install-ai-agent-skills-with-the-npx-skills-cli","How to Install AI Agent Skills with the npx skills CLI",[429,8559,8560,8561,1253],{},"Installation is a single command with the ",[443,8562,8565],{"href":8563,"rel":8564},"https:\u002F\u002Fgithub.com\u002Fvercel-labs\u002Fskills",[447],"skills CLI",[919,8567,8569],{"className":1027,"code":8568,"language":1029,"meta":424,"style":424},"npx skills add https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fscaffold-nuxt-cloudflare-app-skill.git -g\n",[494,8570,8571],{"__ignoreMap":424},[927,8572,8573,8575,8578,8580,8583],{"class":929,"line":930},[927,8574,7592],{"class":1036},[927,8576,8577],{"class":1040}," skills",[927,8579,1050],{"class":1040},[927,8581,8582],{"class":1040}," https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fscaffold-nuxt-cloudflare-app-skill.git",[927,8584,8585],{"class":1040}," -g\n",[429,8587,8588,8589],{},"The CLI clones the repo, finds the skill, and asks which of the 77 supported agents should get it:\n",[432,8590],{"alt":8591,"src":8592},"Command line interface showing the installation of the Nuxt scaffolding skill using the npx skills add CLI command","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20AI%20Agent%20Skills%20Replace%20Nuxt%20App%20Scaffolding%20Scripts\u002Fnpx-skills-add-scaffold-nuxt-installation.webp",[429,8594,8595,8596,8599,8600,8603,8604],{},"We went with ",[440,8597,8598],{},"Symlink"," (the recommended method), which installs the skill once in ",[494,8601,8602],{},"~\u002F.agents\u002Fskills"," and points every selected agent to this single copy.\n",[432,8605],{"alt":8606,"src":8607},"Terminal screen displaying the installation summary and symlink setup for the centralized agent skills","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20AI%20Agent%20Skills%20Replace%20Nuxt%20App%20Scaffolding%20Scripts\u002Fnpx-skills-installation-summary-details.webp",[484,8609,8610],{},[487,8611,8612],{},[894,8613,8614,8615,8617],{},"Please refer to this article, ",[443,8616,358],{"href":359},", on how to centralise agent skills in a single source of truth.",[429,8619,8620],{},"Opening Claude Code confirms the skill is successfully installed.",[429,8622,8623],{},[432,8624],{"alt":8625,"src":8626},"Claude Code command line interface showing the newly installed scaffold-nuxt slash command active and ready for use","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20AI%20Agent%20Skills%20Replace%20Nuxt%20App%20Scaffolding%20Scripts\u002Fclaude-code-scaffold-nuxt-slash-command-active.webp",[429,8628,8629],{},"From there, a natural-language prompt is all it takes:",[2472,8631,8632],{},[429,8633,8634],{},"\"Scaffold a new Nuxt app deployed to Cloudflare Workers — Nuxt UI, a blog section, and a D1 database\"",[429,8636,8637,8638,8642],{},"The skill is open source; check out the ",[443,8639,8641],{"href":8302,"rel":8640},[447],"GitHub repo"," and give it a try.",[1611,8644,8645],{},"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":1056,"depth":1063,"links":8647},[8648,8649,8650,8651,8652],{"id":8120,"depth":1056,"text":8121},{"id":8260,"depth":1056,"text":8261},{"id":8295,"depth":1056,"text":8296},{"id":8470,"depth":1056,"text":8471},{"id":8556,"depth":1056,"text":8557},[1631],"2026-08-25","Scaffold Nuxt on Cloudflare Workers easily. Learn why we replaced brittle shell scripts with AI agent skills and how to install them with npx skills.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20AI%20Agent%20Skills%20Replace%20Nuxt%20App%20Scaffolding%20Scripts\u002FEN-How-AI-Agent-Skills-Replace-Nuxt-App-Scaffolding-Scripts.webp","Nuxt Scaffolding on Cloudflare: Scripts vs AI Skills - Comparing shell scripts and intelligent AI agent skills for scaffolding Nuxt applications.",{"schemaOrg":8659,"robots":1665,"sitemap":8661},[8660],{"@type":1642,"headline":366,"description":8655,"image":8656},{"lastmod":8654},{"title":8663,"description":8655,"ogTitle":366,"ogDescription":8655,"twitterTitle":366,"twitterDescription":8655},"Nuxt Scaffolding on Cloudflare: Scripts vs AI Skills",[8665,6217,8666,8667],"Nuxt","AI Agent","Scaffolding","NXF2Lnd-1xZXVg9jQtNTE4K5fB8GBw1eOmA1GHAhr6s",{"id":8670,"title":414,"author":1673,"body":8671,"category":9427,"date":9429,"description":9430,"extension":1636,"image":9431,"imageAlt":9432,"isPublished":1059,"meta":9433,"minRead":1902,"navigation":1059,"path":69,"seo":9438,"stem":416,"tags":9439,"updatedAt":1673,"__hash__":9441},"article\u002Fen\u002Farticle\u002Fuse-cloudflare-as-ai-memory.md",{"type":426,"value":8672,"toc":9409},[8673,8677,8680,8683,8687,8690,8704,8708,8715,8728,8731,8734,8775,8779,8861,8865,8890,8987,8998,9002,9007,9047,9071,9075,9080,9147,9152,9156,9189,9195,9233,9237,9269,9273,9281,9285,9315,9319,9359,9361,9364,9367,9370,9372,9406],[473,8674,8676],{"id":8675},"the-importance-of-persistent-ai-memory-for-agents","The Importance of Persistent AI Memory for Agents",[429,8678,8679],{},"As AI assistants become integrated into our daily lives, we frequently encounter the blank context issue. The decisions made last week are forgotten, requiring us to input the same tech stack details, and set the user preferences all over again.",[429,8681,8682],{},"Instead of starting from scratch every time, we need to build a memory system that evolves, continuously understands a user's decisions and eliminates the need to repeat context.",[473,8684,8686],{"id":8685},"self-hosted-vs-built-in-ai-memory-systems","Self-Hosted vs. Built-In AI Memory Systems",[429,8688,8689],{},"Many AI agents come with built-in memory, but we don't just use one agent for all purposes. We use Claude for architecting and designing a project; Kimi for coding; and ChatGPT for research. The context is not shared among these agents; it remains siloed per agent.",[429,8691,8692,8693,8698,8699,8703],{},"From a software engineering point of view, we don't trust black boxes. We need AI memory system that is observable, auditable, and under our control. The open sourced project, ",[443,8694,8697],{"href":8695,"rel":8696},"https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fsecond-brain-cloudflare\u002Ftree\u002Fmain",[447],"Second Brain",", forked from ",[443,8700,8701],{"href":8701,"rel":8702},"https:\u002F\u002Fgithub.com\u002Frahilp\u002Fsecond-brain-cloudflare",[447],", provides a persistent and self-hosted memory system with Model Context Protocol (MCP) support.  Any compatible AI agents such as Claude, ChatGPT, Kimi Code can share the same context.",[473,8705,8707],{"id":8706},"how-to-build-a-second-brain-ai-memory-on-cloudflare","How to Build a Second Brain AI Memory on Cloudflare",[429,8709,8710,8711,8714],{},"The Second Brain memory system is deployed on ",[440,8712,8713],{},"Cloudflare Workers",", which provides globally distributed, low-latency execution server infrastructure. This allows the memory recall and other operations to execute with minimal latency to the AI’s reasoning loop.",[429,8716,597,8717,8720,8721,8724,8725,8727],{},[440,8718,8719],{},"Workers AI"," embedding model is used for generating the embeddings. These embeddings are stored in ",[440,8722,8723],{},"Cloudflare Vectorize",", which is a globally distributed vector database. The ",[440,8726,8723],{}," performs the cosine similarity search for semantically related memories.",[429,8729,8730],{},"Duplication detection and smart merging mechanisms are implemented in Second Brain. Content with less than 85% similarity is stored, otherwise it is blocked or marked as a duplicate candidate. Text exceeding 1,600 characters is split at sentence or line-break boundaries with 200-character overlap to prevent loss of context. Then each chunk is embedded as a vector which allows precise matching.",[429,8732,8733],{},"The following tools are exposed as MCP interfaces to be used in AI agents:",[484,8735,8736,8742,8748,8754,8760,8766,8772],{},[487,8737,8738,8741],{},[494,8739,8740],{},"remember",": Store ideas, decisions, preferences, and project context",[487,8743,8744,8747],{},[494,8745,8746],{},"append",": Add an update to an existing memory",[487,8749,8750,8753],{},[494,8751,8752],{},"update",": Replace an existing memory",[487,8755,8756,8759],{},[494,8757,8758],{},"recall",": Find memories by meaning rather than exact wording",[487,8761,8762,8765],{},[494,8763,8764],{},"list_recent",": Browse recently saved memories",[487,8767,8768,8771],{},[494,8769,8770],{},"forget",": Permanently delete a memory",[487,8773,8774],{},"`link\u002Fconnections``: Connect related memories (v2 graph feature)",[874,8776,8778],{"id":8777},"setup-second-brain-on-cloudflare","Setup Second Brain on Cloudflare",[532,8780,8781,8798,8805,8812,8819,8826,8837,8844,8847,8854],{},[487,8782,4217,8783,8786,8787,8792,8793,8797],{},[494,8784,8785],{},"Deploy to Cloudflare"," at the ",[443,8788,8791],{"href":8789,"rel":8790},"https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fsecond-brain-cloudflare",[447],"Github repo"," page. [[",[432,8794],{"alt":8795,"src":8796},"GitHub page with the Deploy to Cloudflare button highlighted","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fdeploy-to-cloudflare-button.webp","]]",[487,8799,8800,8801],{},"Fill out the Cloudflare Worker form.\n",[432,8802],{"alt":8803,"src":8804},"Cloudflare Workers deployment configuration form","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fcloudflare-worker-deployment-form.webp",[487,8806,8807,8808],{},"Enter '384' for Dimensions; select 'cosine' for Metric; and click the Deploy button.\n",[432,8809],{"alt":8810,"src":8811},"Cloudflare Vectorize database creation settings screen","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fcloudflare-vectorize-configuration.webp",[487,8813,8814,8815],{},"The following is the overview of the Second Brain in Cloudflare Worker\n",[432,8816],{"alt":8817,"src":8818},"Overview dashboard of the deployed Second Brain worker","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fcloudflare-worker-second-brain-overview.webp",[487,8820,8821,8822],{},"Click on 'Settings', then click edit icon for 'AUTH_TOKEN' for creating a token\n",[432,8823],{"alt":8824,"src":8825},"Cloudflare Worker variable settings highlighting AUTH_TOKEN","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fcloudflare-worker-auth-token-settings.webp",[487,8827,8828,8829,8833],{},"Click the 'Rotate' link for entering a new value           ",[432,8830],{"alt":8831,"src":8832},"AUTH_TOKEN variable modification and rotation screen","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fcloudflare-worker-auth-token-rotate.webp",[432,8834],{"alt":8835,"src":8836},"Entering the generated random string into the AUTH_TOKEN value field","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fcloudflare-worker-auth-token-value-input.webp",[487,8838,8839,8840,8843],{},"Run the command ",[494,8841,8842],{},"openssl rand -base64 32"," at macOS terminal to create a random value and paste it in the 'Value' input field.",[487,8845,8846],{},"Click the 'Deploy' button to update the new value of 'AUTH_TOKEN'.",[487,8848,8849,8850],{},"Open the Second Brain worker url on the web browser\n",[432,8851],{"alt":8852,"src":8853},"Second Brain Web UI login screen with Bearer Token input","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fsecond-brain-web-ui-login.webp",[487,8855,8856,8857,8860],{},"Enter the created 'AUTH_TOKEN' in the ",[494,8858,8859],{},"Bearer token"," input field and click 'Connect' button to login to the Web UI.",[874,8862,8864],{"id":8863},"integrating-claude-desktop-via-mcp","Integrating Claude Desktop via MCP",[532,8866,8867,8874,8881],{},[487,8868,8869,8870],{},"Click on 'Customize' at Claude Desktop.\n",[432,8871],{"alt":8872,"src":8873},"Claude Desktop interface pointing to the Customize button","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fclaude-desktop-customize-button.webp",[487,8875,8876,8877],{},"Click on 'Developer' to manually edit the MCP Servers config file\n",[432,8878],{"alt":8879,"src":8880},"Claude Desktop Developer settings menu to access MCP config","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fclaude-desktop-developer-menu.webp",[487,8882,8883,8884,8886,8887],{},"Add the following code to the ",[494,8885,7556],{}," section in",[494,8888,8889],{},"claude_desktop_config.json",[919,8891,8893],{"className":2865,"code":8892,"language":2867,"meta":424,"style":424},"    \"second-brain\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"mcp-remote\",\n        \"https:\u002F\u002F\u003Cyour-worker-url>\u002Fmcp\",\n        \"--header\",\n        \"Authorization: Bearer \u003Cyour-token>\"\n      ]\n    }\n",[494,8894,8895,8908,8926,8938,8948,8959,8970,8979,8983],{"__ignoreMap":424},[927,8896,8897,8899,8902,8904,8906],{"class":929,"line":930},[927,8898,7567],{"class":941},[927,8900,8901],{"class":1040},"second-brain",[927,8903,3650],{"class":941},[927,8905,578],{"class":937},[927,8907,2874],{"class":941},[927,8909,8910,8912,8914,8916,8918,8920,8922,8924],{"class":929,"line":1056},[927,8911,7580],{"class":941},[927,8913,7583],{"class":933},[927,8915,3650],{"class":941},[927,8917,1253],{"class":941},[927,8919,3240],{"class":941},[927,8921,7592],{"class":1040},[927,8923,3650],{"class":941},[927,8925,7597],{"class":941},[927,8927,8928,8930,8932,8934,8936],{"class":929,"line":1063},[927,8929,7580],{"class":941},[927,8931,7604],{"class":933},[927,8933,3650],{"class":941},[927,8935,1253],{"class":941},[927,8937,7611],{"class":941},[927,8939,8940,8942,8944,8946],{"class":929,"line":1070},[927,8941,7616],{"class":941},[927,8943,7619],{"class":1040},[927,8945,3650],{"class":941},[927,8947,7597],{"class":941},[927,8949,8950,8952,8955,8957],{"class":929,"line":1891},[927,8951,7616],{"class":941},[927,8953,8954],{"class":1040},"https:\u002F\u002F\u003Cyour-worker-url>\u002Fmcp",[927,8956,3650],{"class":941},[927,8958,7597],{"class":941},[927,8960,8961,8963,8966,8968],{"class":929,"line":1896},[927,8962,7616],{"class":941},[927,8964,8965],{"class":1040},"--header",[927,8967,3650],{"class":941},[927,8969,7597],{"class":941},[927,8971,8972,8974,8977],{"class":929,"line":1902},[927,8973,7616],{"class":941},[927,8975,8976],{"class":1040},"Authorization: Bearer \u003Cyour-token>",[927,8978,1923],{"class":941},[927,8980,8981],{"class":929,"line":2238},[927,8982,7695],{"class":941},[927,8984,8985],{"class":929,"line":1667},[927,8986,7700],{"class":941},[429,8988,8989,8993,8994],{},[432,8990],{"alt":8991,"src":8992},"Claude Desktop MCP configuration JSON containing the Second Brain server","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fclaude-desktop-mcp-config-json.webp","\n4. Restart Claude Desktop and check the 'Local MCP servers'. The status says 'running'",[432,8995],{"alt":8996,"src":8997},"Claude Desktop displaying running status for the Second Brain MCP server","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fclaude-desktop-mcp-status-running.webp",[874,8999,9001],{"id":9000},"integrating-claude-code-via-mcp","Integrating Claude Code via MCP",[484,9003,9004],{},[487,9005,9006],{},"Run the following command to add the MCP",[919,9008,9010],{"className":2267,"code":9009,"language":2269,"meta":424,"style":424},"claude mcp add --transport http second-brain https:\u002F\u002F\u003Cyour-worker-url>\u002Fmcp\n",[494,9011,9012],{"__ignoreMap":424},[927,9013,9014,9017,9020,9022,9025,9028,9031,9034,9036,9039,9042,9044],{"class":929,"line":930},[927,9015,9016],{"class":1036},"claude",[927,9018,9019],{"class":1040}," mcp",[927,9021,1050],{"class":1040},[927,9023,9024],{"class":1040}," --transport",[927,9026,9027],{"class":1040}," http",[927,9029,9030],{"class":1040}," second-brain",[927,9032,9033],{"class":1040}," https:\u002F\u002F",[927,9035,5531],{"class":941},[927,9037,9038],{"class":1040},"your-worker-ur",[927,9040,9041],{"class":937},"l",[927,9043,1221],{"class":941},[927,9045,9046],{"class":1040},"\u002Fmcp\n",[484,9048,9049,9055],{},[487,9050,9051,9052],{},"Claude Code detects that the endpoint requires OAuth and will open the login page at the web browser for entering ",[494,9053,9054],{},"AUTH_TOKEN",[487,9056,9057,9058,9061,9062,9065,9066,460],{},"Create the ",[494,9059,9060],{},"CLAUDE.md"," file in ",[494,9063,9064],{},"~\u002F.claude"," folder with the instructions from ",[443,9067,9070],{"href":9068,"rel":9069},"https:\u002F\u002Fgithub.com\u002Frahilp\u002Fsecond-brain-cloudflare\u002Fblob\u002Fmain\u002FAI_Instructions\u002FCLAUDE_INSTRUCTIONS.md",[447],"CLAUDE_INSTRUCTIONS.md",[874,9072,9074],{"id":9073},"integrating-gemini-cli-via-mcp","Integrating Gemini CLI via MCP",[532,9076,9077],{},[487,9078,9079],{},"Add the following MCP server settings to '.\u002F.gemini\u002Fsettings.json'",[919,9081,9083],{"className":2865,"code":9082,"language":2867,"meta":424,"style":424},"    \"second-brain\": {\n      \"httpUrl\": \"https:\u002F\u002F\u003Cyour-worker-url>\u002Fmcp\",\n      \"oauth\": {\n        \"enabled\": true\n      }\n    }\n",[494,9084,9085,9097,9115,9127,9139,9143],{"__ignoreMap":424},[927,9086,9087,9089,9091,9093,9095],{"class":929,"line":930},[927,9088,7567],{"class":941},[927,9090,8901],{"class":1040},[927,9092,3650],{"class":941},[927,9094,578],{"class":937},[927,9096,2874],{"class":941},[927,9098,9099,9101,9103,9105,9107,9109,9111,9113],{"class":929,"line":1056},[927,9100,7580],{"class":941},[927,9102,7807],{"class":933},[927,9104,3650],{"class":941},[927,9106,1253],{"class":941},[927,9108,3240],{"class":941},[927,9110,8954],{"class":1040},[927,9112,3650],{"class":941},[927,9114,7597],{"class":941},[927,9116,9117,9119,9121,9123,9125],{"class":929,"line":1063},[927,9118,7580],{"class":941},[927,9120,7826],{"class":933},[927,9122,3650],{"class":941},[927,9124,1253],{"class":941},[927,9126,2904],{"class":941},[927,9128,9129,9131,9133,9135,9137],{"class":929,"line":1070},[927,9130,7616],{"class":941},[927,9132,7839],{"class":1036},[927,9134,3650],{"class":941},[927,9136,1253],{"class":941},[927,9138,1353],{"class":941},[927,9140,9141],{"class":929,"line":1891},[927,9142,7850],{"class":941},[927,9144,9145],{"class":929,"line":1896},[927,9146,7700],{"class":941},[532,9148,9149],{"start":1056},[487,9150,9151],{},"Start the Gemini CLI",[874,9153,9155],{"id":9154},"test-second-brain-in-ai-agents","Test Second Brain in AI Agents",[532,9157,9158,9168,9182],{},[487,9159,9160,9161,9163,9164],{},"Started with a simple brand palette settings in '",[440,9162,7508],{},"', the Second Brain is not called.\n",[432,9165],{"alt":9166,"src":9167},"First test in Claude Desktop without the Second Brain memory layer active","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fclaude-desktop-first-run-brand-palette.webp",[487,9169,9170,9171,9174,9175,9177,9178],{},"Tried with the keyword, 'remember', only ",[494,9172,9173],{},"memory_user-edits"," tools in '",[440,9176,7508],{},"' are used but not Second Brain.\n",[432,9179],{"alt":9180,"src":9181},"Claude Desktop falling back to local built-in user edits instead of Second Brain","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fclaude-desktop-remember-built-in-tool-fallback.webp",[487,9183,9184,9185,9188],{},"Tried the the following prompt in '",[440,9186,9187],{},"Claude Code","', Second Brain was called.",[919,9190,9193],{"className":9191,"code":9192,"language":4598},[4596],"Remember Our brand palette uses `#1a1a2e` as primary, `#16213e` as secondary, and `#e94560` as accent. Never use pure black.\"\n",[494,9194,9192],{"__ignoreMap":424},[429,9196,9197,9201,9202,9205,9209,9210,9213,9214,9216,9217,9221,9222,9225,9226,9209,9230],{},[432,9198],{"alt":9199,"src":9200},"Claude Code terminal window showing successful trigger of the Second Brain MCP","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fclaude-code-second-brain-mcp-called.webp","\n4. Verified the colour settings in the ",[440,9203,9204],{},"Second Brain at Cloudflare",[432,9206],{"alt":9207,"src":9208},"Verifying the saved brand color codes in the Second Brain database Web UI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fsecond-brain-web-ui-color-verification.webp","\n- ",[894,9211,9212],{},"The reason Claude Code worked was because the CLAUDE_INSTRUCTIONS.md contains the 'Second Brain' keywords.","\n5. Included 'Second Brain' as keywords in '",[440,9215,7508],{},"',  need to be explicitly specified to store to and retrieve from the Second Brain memory layer.\n",[432,9218],{"alt":9219,"src":9220},"Triggering Second Brain in Claude Desktop by explicitly mentioning keywords","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fclaude-desktop-second-brain-explicit-trigger.webp","\n6. The keywords, 'Second Brain', need to be mentioned in the ",[440,9223,9224],{},"Gemini CLI"," to trigger the Second Brain MCP.\n",[432,9227],{"alt":9228,"src":9229},"Gemini CLI terminal window demonstrating successful Second Brain MCP calls","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fgemini-cli-second-brain-trigger.webp",[894,9231,9232],{},"Adding similar instructions to GEMINI.md like what has been done in CLAUDE_INSTRUCTIONS.md will trigger the Second Brain without mentioning the keywords.",[874,9234,9236],{"id":9235},"web-browser-extensions","Web Browser Extensions",[484,9238,9239,9242],{},[487,9240,9241],{},"Extensions are available for Chrome, Firefox and Microsoft Edge web browsers.",[487,9243,9244,9245],{},"The extensions are for\n",[484,9246,9247,9253,9259],{},[487,9248,9249,9252],{},[440,9250,9251],{},"Capture the current page"," — saves the title and URL to the Second Brain",[487,9254,9255,9258],{},[440,9256,9257],{},"Capture highlighted text"," — select any text on a page before clicking capture; the excerpt is saved alongside the title and URL",[487,9260,9261,9264,9265,9268],{},[440,9262,9263],{},"Add a note"," — type context or ",[494,9266,9267],{},"#hashtags"," in the popup before saving; hashtags are automatically extracted as tags",[874,9270,9272],{"id":9271},"syncing-personal-knowledge-with-the-obsidian-plugin","Syncing Personal Knowledge with the Obsidian Plugin",[484,9274,9275,9278],{},[487,9276,9277],{},"Obsidian plugin is available to sync the notes from the Obsidian Vault to Second Brain at Cloudflare.",[487,9279,9280],{},"Notes can be tagged for syncing to the Second Brain",[2125,9282,9284],{"id":9283},"install-obsidian-plugin","Install Obsidian Plugin",[532,9286,9287,9294,9301,9308],{},[487,9288,9289,9290],{},"Open Obsidian → Settings → Community Plugins\n",[432,9291],{"alt":9292,"src":9293},"Obsidian settings panel navigating to the Community Plugins section","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fobsidian-settings-community-plugins.webp",[487,9295,9296,9297],{},"Click on 'Browse' button\n",[432,9298],{"alt":9299,"src":9300},"Obsidian community plugins search page showing the Browse button","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fobsidian-community-plugins-browse.webp",[487,9302,9303,9304],{},"Search for 'Second Brain Sync'\n",[432,9305],{"alt":9306,"src":9307},"Searching for Second Brain Sync plugin in Obsidian marketplace","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fobsidian-community-plugins-search-second-brain.webp",[487,9309,9310,9311],{},"Click 'Install' button then 'Enable' button\n",[432,9312],{"alt":9313,"src":9314},"Installing and enabling the Second Brain Sync plugin in Obsidian","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fobsidian-plugin-install-and-enable.webp",[2125,9316,9318],{"id":9317},"configure-obsidian-plugin","Configure Obsidian Plugin",[532,9320,9321,9324,9331,9338,9345,9352],{},[487,9322,9323],{},"Open Obsidian → Settings → Second Brain Sync",[487,9325,9326,9327],{},"Enter the 'URL' and 'Auth token'\n",[432,9328],{"alt":9329,"src":9330},"Entering Worker URL and Auth Token in Obsidian plugin settings","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fobsidian-plugin-configuration-credentials.webp",[487,9332,9333,9334],{},"Click 'Test' button to verify it is connected.\n",[432,9335],{"alt":9336,"src":9337},"Obsidian plugin connection test showing successful verification","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fobsidian-plugin-connection-test-success.webp",[487,9339,9340,9341],{},"Configure the sync behaviours. Set the 'Sync tag' and enable 'Auto-sync on save'.\n",[432,9342],{"alt":9343,"src":9344},"Configuring Sync Tag and enabling Auto-sync on save in Obsidian","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fobsidian-plugin-sync-behavior-settings.webp",[487,9346,9347,9348],{},"Create a note in Obsidian with the tag, 'second-brain', as it was configured as the 'Sync tag'.\n",[432,9349],{"alt":9350,"src":9351},"Creating a new Obsidian note tagged with second-brain for synchronization","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fobsidian-note-with-sync-tag.webp",[487,9353,9354,9355],{},"The note has been saved and synced to the Second Brain deployed at Cloudflare.\n",[432,9356],{"alt":9357,"src":9358},"Verifying the successfully synchronized Obsidian note in Second Brain Web UI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002Fsecond-brain-web-ui-synced-note-verification.webp",[473,9360,2536],{"id":2535},[429,9362,9363],{},"Second Brain provides an open-source solution to one of the most frustrating issues in AI: persistent memory. By combining it with Cloudflare infrastructure, it delivers a fully self-hosted memory layer that is globally distributed with low latency. The MCP tools built into Second Brain make this memory portable across all AI agents.",[429,9365,9366],{},"The Obsidian plugin extends the Second Brain into personal knowledge management. Notes in an Obsidian vault can be selectively synchronised to Second Brain, transforming raw notes into structured context that AI agents can semantically understand and retrieve.",[429,9368,9369],{},"By combining self-hosting, semantic search, and standards-based MCP integration; Second Brain proves to be more than just a memory layer but a practical foundation for building an AI ecosystem.",[473,9371,8017],{"id":6123},[484,9373,9374,9380,9386,9393,9400],{},[487,9375,9376],{},[443,9377,9378],{"href":9378,"rel":9379},"https:\u002F\u002Fwww.thesecondbrain.dev\u002F",[447],[487,9381,9382],{},[443,9383,9384],{"href":9384,"rel":9385},"https:\u002F\u002Fgithub.com\u002Frahilp\u002Fsecond-brain-cloudflare\u002Fwiki\u002FHow-It-Works",[447],[487,9387,9388],{},[443,9389,9392],{"href":9390,"rel":9391},"https:\u002F\u002Fgithub.com\u002Frahilp\u002Fsecond-brain-cloudflare\u002Fwiki\u002FConnect-to-AI-Clients",[447],"Connect to AI Clients",[487,9394,9395],{},[443,9396,9399],{"href":9397,"rel":9398},"https:\u002F\u002Fgithub.com\u002Frahilp\u002Fsecond-brain-cloudflare\u002Fwiki\u002FObsidian-Plugin",[447],"Second Brain Obsidian Plugin",[487,9401,9402],{},[443,9403,9404],{"href":9404,"rel":9405},"https:\u002F\u002Fgithub.com\u002Frahilp\u002Fsecond-brain-obsidian-plugin",[447],[1611,9407,9408],{},"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 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}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}",{"title":424,"searchDepth":1056,"depth":1063,"links":9410},[9411,9412,9413,9425,9426],{"id":8675,"depth":1056,"text":8676},{"id":8685,"depth":1056,"text":8686},{"id":8706,"depth":1056,"text":8707,"children":9414},[9415,9416,9417,9418,9419,9420,9421],{"id":8777,"depth":1063,"text":8778},{"id":8863,"depth":1063,"text":8864},{"id":9000,"depth":1063,"text":9001},{"id":9073,"depth":1063,"text":9074},{"id":9154,"depth":1063,"text":9155},{"id":9235,"depth":1063,"text":9236},{"id":9271,"depth":1063,"text":9272,"children":9422},[9423,9424],{"id":9283,"depth":1070,"text":9284},{"id":9317,"depth":1070,"text":9318},{"id":2535,"depth":1056,"text":2536},{"id":6123,"depth":1056,"text":8017},[9428,1631],"cloudflare","2026-08-07","Learn how to build a persistent, self-hosted AI memory system on Cloudflare using Second Brain and MCP. Share context across Claude, Gemini, and Obsidian.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Cloudflare%20as%20AI%20memory\u002FEN-Use-Cloudflare-as-AI-memory.webp","A personal self-hosted AI memory system deployed on Cloudflare Workers and Vectorize using the Model Context Protocol (MCP) and Obsidian sync.",{"schemaOrg":9434,"robots":1665,"sitemap":9437},[9435],{"@type":1642,"headline":9436,"description":9430},"Build a Self-Hosted AI Memory System with Cloudflare & MCP",{"lastmod":9429},{"title":9436,"description":9430,"ogTitle":414,"ogDescription":9430,"twitterTitle":414,"twitterDescription":9430},[6217,6904,9440,8697,4054],"AI Memory","i-n5KfCSdIReLHWXO0pss_aKBTXq5lNG61z0LAefVgk",{"id":9443,"title":398,"author":424,"body":9444,"category":9956,"date":9957,"description":9958,"extension":1636,"image":9959,"imageAlt":9960,"isPublished":1059,"meta":9961,"minRead":1070,"navigation":1059,"path":61,"seo":9965,"stem":400,"tags":9966,"updatedAt":1673,"__hash__":9969},"article\u002Fen\u002Farticle\u002Fswitch-between-multiple-cloudflare-warp-orgs-on-mac.md",{"type":426,"value":9445,"toc":9949},[9446,9450,9453,9460,9464,9470,9473,9476,9480,9483,9490,9506,9800,9909,9911,9914,9916,9946],[473,9447,9449],{"id":9448},"what-is-cloudflare-warp","What Is Cloudflare WARP?",[429,9451,9452],{},"Cloudflare WARP is a client-side application that routes specified device traffic through Cloudflare's global network instead of directly out to the public internet.",[429,9454,9455,9456,9459],{},"It creates an encrypted tunnel built on the ",[440,9457,9458],{},"WireGuard"," protocol, securing traffic from the device to the nearest Cloudflare data center. Policies can then be created in your Cloudflare dashboard to filter, log, inspect, or route this incoming traffic.",[473,9461,9463],{"id":9462},"why-do-we-need-cloudflare-warp","Why Do We Need Cloudflare WARP?",[429,9465,9466,9467,460],{},"To securely expose internal resources—such as private web services or SaaS applications—to employees, contractors, and other stakeholders, the Cloudflare WARP client is the as the client-side enforcement point for ",[440,9468,9469],{},"Zero Trust Network Access (ZTNA)",[429,9471,9472],{},"The Cloudflare WARP client is installed on a user’s laptop or phone. It requires users to authenticate and meet specific security posture checks (such as coming from an approved IP range, using a registered email domain, or running an active firewall) before granting access.",[429,9474,9475],{},"By tunneling device traffic directly to Cloudflare, the user's identity, device, and policies are verified before requests ever reach internal resources. As a result, internal resources are never exposed to the public internet, and every single request is fully logged and audited.",[473,9477,9479],{"id":9478},"supporting-multiple-warp-profiles-on-one-device","Supporting Multiple WARP Profiles on One Device",[429,9481,9482],{},"When users need to switch between personal and corporate Cloudflare accounts, or when system administrators manage multiple tenants, supporting multiple WARP profiles on a single device becomes crucial.",[429,9484,9485,9486,9489],{},"To achieve this on macOS, we can use a ",[494,9487,9488],{},".mobileconfig"," MDM profile file to define and register the different WARP environments.",[484,9491,9492,9503],{},[487,9493,9494,9502],{},[443,9495,9498,9499,9501],{"href":9496,"rel":9497},"https:\u002F\u002Fdevelopers.cloudflare.com\u002Fcloudflare-one\u002Fstatic\u002Fmdm\u002Fmultiple-orgs\u002FCloudflareWARP.mobileconfig",[447],"Download a sample ",[494,9500,9488],{}," file"," directly from Cloudflare.",[487,9504,9505],{},"Below is an example of what this configuration looks like:",[919,9507,9511],{"className":9508,"code":9509,"language":9510,"meta":424,"style":424},"language-xml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003C!DOCTYPE plist PUBLIC \"-\u002F\u002FApple\u002F\u002FDTD PLIST 1.0\u002F\u002FEN\" \"http:\u002F\u002Fwww.apple.com\u002FDTDs\u002FPropertyList-1.0.dtd\">\n\u003Cplist version=\"1.0\">\n\u003Cdict>\n  \u003Ckey>PayloadContent\u003C\u002Fkey>\n  \u003Carray>\n    \u003Cdict>\n      \u003Ckey>PayloadDisplayName\u003C\u002Fkey>\n      \u003Cstring>Warp Configuration\u003C\u002Fstring>\n      \u003Ckey>PayloadIdentifier\u003C\u002Fkey>\n      \u003Cstring>com.cloudflare.warp.CB8B22D4-50E1-48E8-8874-A7594627013A\u003C\u002Fstring>\n      \u003Ckey>PayloadOrganization\u003C\u002Fkey>\n      \u003Cstring>Cloudflare Ltd.\u003C\u002Fstring>\n      \u003Ckey>PayloadType\u003C\u002Fkey>\n      \u003Cstring>com.cloudflare.warp\u003C\u002Fstring>\n      \u003Ckey>PayloadUUID\u003C\u002Fkey>\n      \u003Cstring>CB8B22D4-50E1-48E8-8874-A7594627013A\u003C\u002Fstring>\n      \u003Ckey>PayloadVersion\u003C\u002Fkey>\n      \u003Cinteger>1\u003C\u002Finteger>\n      \u003Ckey>configs\u003C\u002Fkey>\n      \u003Carray>\n        \u003Cdict>\n          \u003Ckey>organization\u003C\u002Fkey>\n          \u003Cstring>your-team-name-1\u003C\u002Fstring>\n          \u003Ckey>display_name\u003C\u002Fkey>\n          \u003Cstring>Team 1\u003C\u002Fstring>\n        \u003C\u002Fdict>\n        \u003Cdict>\n          \u003Ckey>organization\u003C\u002Fkey>\n          \u003Cstring>your-team-name-2\u003C\u002Fstring>\n          \u003Ckey>display_name\u003C\u002Fkey>\n          \u003Cstring>Team 2\u003C\u002Fstring>\n        \u003C\u002Fdict>\n      \u003C\u002Farray>\n    \u003C\u002Fdict>\n  \u003C\u002Farray>\n  \u003Ckey>PayloadDisplayName\u003C\u002Fkey>\n  \u003Cstring>Cloudflare WARP\u003C\u002Fstring>\n  \u003Ckey>PayloadIdentifier\u003C\u002Fkey>\n  \u003Cstring>cloudflare_warp\u003C\u002Fstring>\n  \u003Ckey>PayloadOrganization\u003C\u002Fkey>\n  \u003Cstring>Cloudflare, Ltd.\u003C\u002Fstring>\n  \u003Ckey>PayloadRemovalDisallowed\u003C\u002Fkey>\n  \u003Cfalse\u002F>\n  \u003Ckey>PayloadScope\u003C\u002Fkey>\n  \u003Cstring>System\u003C\u002Fstring>\n  \u003Ckey>PayloadType\u003C\u002Fkey>\n  \u003Cstring>Configuration\u003C\u002Fstring>\n  \u003Ckey>PayloadUUID\u003C\u002Fkey>\n  \u003Cstring>2B7763B8-64F6-41EB-AA5E-7761651B8131\u003C\u002Fstring>\n  \u003Ckey>PayloadVersion\u003C\u002Fkey>\n  \u003Cinteger>1\u003C\u002Finteger>\n\u003C\u002Fdict>\n\u003C\u002Fplist>\n","xml",[494,9512,9513,9518,9523,9528,9533,9538,9543,9548,9553,9558,9563,9568,9573,9578,9583,9588,9593,9598,9603,9608,9613,9618,9623,9628,9633,9638,9643,9648,9652,9656,9661,9665,9670,9674,9680,9686,9692,9698,9704,9710,9716,9722,9728,9734,9740,9746,9752,9758,9764,9770,9776,9782,9788,9794],{"__ignoreMap":424},[927,9514,9515],{"class":929,"line":930},[927,9516,9517],{},"\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",[927,9519,9520],{"class":929,"line":1056},[927,9521,9522],{},"\u003C!DOCTYPE plist PUBLIC \"-\u002F\u002FApple\u002F\u002FDTD PLIST 1.0\u002F\u002FEN\" \"http:\u002F\u002Fwww.apple.com\u002FDTDs\u002FPropertyList-1.0.dtd\">\n",[927,9524,9525],{"class":929,"line":1063},[927,9526,9527],{},"\u003Cplist version=\"1.0\">\n",[927,9529,9530],{"class":929,"line":1070},[927,9531,9532],{},"\u003Cdict>\n",[927,9534,9535],{"class":929,"line":1891},[927,9536,9537],{},"  \u003Ckey>PayloadContent\u003C\u002Fkey>\n",[927,9539,9540],{"class":929,"line":1896},[927,9541,9542],{},"  \u003Carray>\n",[927,9544,9545],{"class":929,"line":1902},[927,9546,9547],{},"    \u003Cdict>\n",[927,9549,9550],{"class":929,"line":2238},[927,9551,9552],{},"      \u003Ckey>PayloadDisplayName\u003C\u002Fkey>\n",[927,9554,9555],{"class":929,"line":1667},[927,9556,9557],{},"      \u003Cstring>Warp Configuration\u003C\u002Fstring>\n",[927,9559,9560],{"class":929,"line":2344},[927,9561,9562],{},"      \u003Ckey>PayloadIdentifier\u003C\u002Fkey>\n",[927,9564,9565],{"class":929,"line":2350},[927,9566,9567],{},"      \u003Cstring>com.cloudflare.warp.CB8B22D4-50E1-48E8-8874-A7594627013A\u003C\u002Fstring>\n",[927,9569,9570],{"class":929,"line":2356},[927,9571,9572],{},"      \u003Ckey>PayloadOrganization\u003C\u002Fkey>\n",[927,9574,9575],{"class":929,"line":2361},[927,9576,9577],{},"      \u003Cstring>Cloudflare Ltd.\u003C\u002Fstring>\n",[927,9579,9580],{"class":929,"line":2367},[927,9581,9582],{},"      \u003Ckey>PayloadType\u003C\u002Fkey>\n",[927,9584,9585],{"class":929,"line":3309},[927,9586,9587],{},"      \u003Cstring>com.cloudflare.warp\u003C\u002Fstring>\n",[927,9589,9590],{"class":929,"line":3320},[927,9591,9592],{},"      \u003Ckey>PayloadUUID\u003C\u002Fkey>\n",[927,9594,9595],{"class":929,"line":3325},[927,9596,9597],{},"      \u003Cstring>CB8B22D4-50E1-48E8-8874-A7594627013A\u003C\u002Fstring>\n",[927,9599,9600],{"class":929,"line":3333},[927,9601,9602],{},"      \u003Ckey>PayloadVersion\u003C\u002Fkey>\n",[927,9604,9605],{"class":929,"line":3863},[927,9606,9607],{},"      \u003Cinteger>1\u003C\u002Finteger>\n",[927,9609,9610],{"class":929,"line":3869},[927,9611,9612],{},"      \u003Ckey>configs\u003C\u002Fkey>\n",[927,9614,9615],{"class":929,"line":3878},[927,9616,9617],{},"      \u003Carray>\n",[927,9619,9620],{"class":929,"line":4529},[927,9621,9622],{},"        \u003Cdict>\n",[927,9624,9625],{"class":929,"line":4982},[927,9626,9627],{},"          \u003Ckey>organization\u003C\u002Fkey>\n",[927,9629,9630],{"class":929,"line":4991},[927,9631,9632],{},"          \u003Cstring>your-team-name-1\u003C\u002Fstring>\n",[927,9634,9635],{"class":929,"line":4999},[927,9636,9637],{},"          \u003Ckey>display_name\u003C\u002Fkey>\n",[927,9639,9640],{"class":929,"line":5007},[927,9641,9642],{},"          \u003Cstring>Team 1\u003C\u002Fstring>\n",[927,9644,9645],{"class":929,"line":5012},[927,9646,9647],{},"        \u003C\u002Fdict>\n",[927,9649,9650],{"class":929,"line":5019},[927,9651,9622],{},[927,9653,9654],{"class":929,"line":5027},[927,9655,9627],{},[927,9657,9658],{"class":929,"line":5035},[927,9659,9660],{},"          \u003Cstring>your-team-name-2\u003C\u002Fstring>\n",[927,9662,9663],{"class":929,"line":5046},[927,9664,9637],{},[927,9666,9667],{"class":929,"line":5054},[927,9668,9669],{},"          \u003Cstring>Team 2\u003C\u002Fstring>\n",[927,9671,9672],{"class":929,"line":5061},[927,9673,9647],{},[927,9675,9677],{"class":929,"line":9676},34,[927,9678,9679],{},"      \u003C\u002Farray>\n",[927,9681,9683],{"class":929,"line":9682},35,[927,9684,9685],{},"    \u003C\u002Fdict>\n",[927,9687,9689],{"class":929,"line":9688},36,[927,9690,9691],{},"  \u003C\u002Farray>\n",[927,9693,9695],{"class":929,"line":9694},37,[927,9696,9697],{},"  \u003Ckey>PayloadDisplayName\u003C\u002Fkey>\n",[927,9699,9701],{"class":929,"line":9700},38,[927,9702,9703],{},"  \u003Cstring>Cloudflare WARP\u003C\u002Fstring>\n",[927,9705,9707],{"class":929,"line":9706},39,[927,9708,9709],{},"  \u003Ckey>PayloadIdentifier\u003C\u002Fkey>\n",[927,9711,9713],{"class":929,"line":9712},40,[927,9714,9715],{},"  \u003Cstring>cloudflare_warp\u003C\u002Fstring>\n",[927,9717,9719],{"class":929,"line":9718},41,[927,9720,9721],{},"  \u003Ckey>PayloadOrganization\u003C\u002Fkey>\n",[927,9723,9725],{"class":929,"line":9724},42,[927,9726,9727],{},"  \u003Cstring>Cloudflare, Ltd.\u003C\u002Fstring>\n",[927,9729,9731],{"class":929,"line":9730},43,[927,9732,9733],{},"  \u003Ckey>PayloadRemovalDisallowed\u003C\u002Fkey>\n",[927,9735,9737],{"class":929,"line":9736},44,[927,9738,9739],{},"  \u003Cfalse\u002F>\n",[927,9741,9743],{"class":929,"line":9742},45,[927,9744,9745],{},"  \u003Ckey>PayloadScope\u003C\u002Fkey>\n",[927,9747,9749],{"class":929,"line":9748},46,[927,9750,9751],{},"  \u003Cstring>System\u003C\u002Fstring>\n",[927,9753,9755],{"class":929,"line":9754},47,[927,9756,9757],{},"  \u003Ckey>PayloadType\u003C\u002Fkey>\n",[927,9759,9761],{"class":929,"line":9760},48,[927,9762,9763],{},"  \u003Cstring>Configuration\u003C\u002Fstring>\n",[927,9765,9767],{"class":929,"line":9766},49,[927,9768,9769],{},"  \u003Ckey>PayloadUUID\u003C\u002Fkey>\n",[927,9771,9773],{"class":929,"line":9772},50,[927,9774,9775],{},"  \u003Cstring>2B7763B8-64F6-41EB-AA5E-7761651B8131\u003C\u002Fstring>\n",[927,9777,9779],{"class":929,"line":9778},51,[927,9780,9781],{},"  \u003Ckey>PayloadVersion\u003C\u002Fkey>\n",[927,9783,9785],{"class":929,"line":9784},52,[927,9786,9787],{},"  \u003Cinteger>1\u003C\u002Finteger>\n",[927,9789,9791],{"class":929,"line":9790},53,[927,9792,9793],{},"\u003C\u002Fdict>\n",[927,9795,9797],{"class":929,"line":9796},54,[927,9798,9799],{},"\u003C\u002Fplist>\n",[484,9801,9802,9812,9825,9835,9840,9856,9868,9885,9900],{},[487,9803,9804,9805,574,9808,9811],{},"Replace ",[494,9806,9807],{},"your-team-name-1",[494,9809,9810],{},"your-team-name-2"," with your respective Cloudflare Zero Trust team names.",[487,9813,8839,9814,9817,9818,9821,9822,9824],{},[494,9815,9816],{},"uuidgen"," in your Terminal to generate unique UUIDs, and use them to replace the placeholder ",[494,9819,9820],{},"PayloadUUID"," values in the ",[494,9823,9488],{}," file.",[487,9826,9827,9828,9831,9832,9834],{},"Make sure that the ",[494,9829,9830],{},"PayloadIdentifier"," string also contains the updated ",[494,9833,9820],{}," to keep the profile distinct.",[487,9836,9837,9838,9824],{},"Save your edited ",[494,9839,9488],{},[487,9841,3893,9842,9845,9846,9849,9850,9852],{},[440,9843,9844],{},"System Settings"," on your Mac, search for ",[440,9847,9848],{},"Profiles",", and select it.",[1847,9851],{},[432,9853],{"alt":9854,"src":9855},"macOS System Settings Profiles pane","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSwitch%20Between%20Multiple%20Cloudflare%20WARP%20Orgs%20on%20Mac\u002Fmacos-system-settings-profiles.webp",[487,9857,4217,9858,9861,9862,9864],{},[440,9859,9860],{},"Install, view or remove..."," to begin adding your new configuration profile.",[1847,9863],{},[432,9865],{"alt":9866,"src":9867},"macOS Profiles install view or remove button","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSwitch%20Between%20Multiple%20Cloudflare%20WARP%20Orgs%20on%20Mac\u002Fmacos-profiles-view-remove.webp",[487,9869,3026,9870,9872,9873,9824,9875,9877,9881],{},[440,9871,715],{}," (plus) icon in the bottom-left corner and select your saved ",[494,9874,9488],{},[1847,9876],{},[432,9878],{"alt":9879,"src":9880},"macOS Profiles plus button to add a new profile","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSwitch%20Between%20Multiple%20Cloudflare%20WARP%20Orgs%20on%20Mac\u002Fmacos-profiles-add-profile.webp",[432,9882],{"alt":9883,"src":9884},"Selecting the mobileconfig file on macOS","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSwitch%20Between%20Multiple%20Cloudflare%20WARP%20Orgs%20on%20Mac\u002Fmacos-select-mobileconfig-file.webp",[487,9886,9887,9888,6851,9890,9893,9894,9896],{},"Select ",[440,9889,1688],{},[440,9891,9892],{},"Install"," to apply the configuration.",[1847,9895],{},[432,9897],{"alt":9898,"src":9899},"Confirming Cloudflare WARP profile installation on macOS","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSwitch%20Between%20Multiple%20Cloudflare%20WARP%20Orgs%20on%20Mac\u002Fmacos-install-cloudflare-warp-profile.webp",[487,9901,9902,9903,9905],{},"Restart your Cloudflare WARP client. You should now see the multi-profile switcher in the user interface:",[1847,9904],{},[432,9906],{"alt":9907,"src":9908},"Cloudflare WARP client with multi-profile switcher on macOS","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSwitch%20Between%20Multiple%20Cloudflare%20WARP%20Orgs%20on%20Mac\u002Fcloudflare-warp-multi-profile-switcher.webp",[473,9910,2536],{"id":2535},[429,9912,9913],{},"The Cloudflare WARP client acts as a critical security point on user devices, making Zero Trust Network Access both robust and highly practical. Keeping internal resources isolated from the public internet ensures that every connection attempt is securely authenticated, evaluated, and audited.",[473,9915,3988],{"id":1582},[484,9917,9918,9925,9932,9939],{},[487,9919,9920],{},[443,9921,9924],{"href":9922,"rel":9923},"https:\u002F\u002Fdevelopers.cloudflare.com\u002Fcloudflare-one\u002Fteam-and-resources\u002Fdevices\u002Fcloudflare-one-client\u002Fdeployment\u002Fmdm-deployment\u002F#prepare-file-for-mdm-deployment",[447],"Managed Deployment Preparation",[487,9926,9927],{},[443,9928,9931],{"href":9929,"rel":9930},"https:\u002F\u002Fdevelopers.cloudflare.com\u002Fcloudflare-one\u002Fteam-and-resources\u002Fdevices\u002Fcloudflare-one-client\u002Fdeployment\u002Fmdm-deployment\u002Fswitch-organizations\u002F",[447],"Switch Between Zero Trust Organizations",[487,9933,9934],{},[443,9935,9938],{"href":9936,"rel":9937},"https:\u002F\u002Fblog.cloudflare.com\u002Fintroducing-warp-connector-paving-the-path-to-any-to-any-connectivity-2\u002F",[447],"Introducing WARP Connector: Paving the Path to Any-to-Any Connectivity",[487,9940,9941],{},[443,9942,9945],{"href":9943,"rel":9944},"https:\u002F\u002Fdevelopers.cloudflare.com\u002Fcloudflare-one\u002Fteam-and-resources\u002Fdevices\u002Fcloudflare-one-client\u002F",[447],"Cloudflare One Client Documentation",[1611,9947,9948],{},"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":1056,"depth":1063,"links":9950},[9951,9952,9953,9954,9955],{"id":9448,"depth":1056,"text":9449},{"id":9462,"depth":1056,"text":9463},{"id":9478,"depth":1056,"text":9479},{"id":2535,"depth":1056,"text":2536},{"id":1582,"depth":1056,"text":3988},[2569,9428],"2026-07-04","Configure and switch multiple Cloudflare WARP organisations on macOS using a .mobileconfig file. A complete MDM guide for IT admins.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSwitch%20Between%20Multiple%20Cloudflare%20WARP%20Orgs%20on%20Mac\u002FEN-Switch-Between-Multiple-Cloudflare-WARP-Orgs-on-Mac.webp","Configure Multiple Cloudflare WARP Profiles on macOS",{"schemaOrg":9962,"robots":1665,"sitemap":9964},[9963],{"@type":1644,"headline":398,"description":9958},{"lastmod":9957},{"title":9960,"description":9958,"ogTitle":398,"ogDescription":9958,"twitterTitle":398,"twitterDescription":9958},[9967,1688,9968,2611],"macOS","MDM","1b-JmgD0tsBcQooHgG1MNPYYvTAdh8f83JMRp2OWhJ8",{"id":9971,"title":350,"author":424,"body":9972,"category":10344,"date":10345,"description":10346,"extension":1636,"image":10347,"imageAlt":10348,"isPublished":1059,"meta":10349,"minRead":1070,"navigation":1059,"path":37,"seo":10353,"stem":352,"tags":10354,"updatedAt":1673,"__hash__":10358},"article\u002Fen\u002Farticle\u002Fai-agent-skills-what-they-are-how-to-create-them.md",{"type":426,"value":9973,"toc":10334},[9974,9978,9988,9999,10060,10066,10070,10073,10082,10088,10092,10147,10158,10164,10167,10219,10223,10226,10233,10236,10247,10251,10295,10298,10315,10317,10328,10331],[473,9975,9977],{"id":9976},"what-is-an-ai-agent-skill","What Is an AI Agent Skill?",[429,9979,9980,9981,9984,9985,9987],{},"An agent skill is a reusable ",[440,9982,9983],{},"set of instructions"," — a standardised procedure that tells an agent how to do a particular kind of task well. It consists of a single Markdown file, ",[494,9986,8271],{},", and can bundle any other files the task requires, such as reference documents, templates, or executable scripts.",[429,9989,9990,9991,9998],{},"Take the ",[443,9992,9995],{"href":9993,"rel":9994},"https:\u002F\u002Fgithub.com\u002Fmattpocock\u002Fskills\u002Fblob\u002F733d312884b3878a9a9cff693c5886943753a741\u002Fskills\u002Fproductivity\u002Fgrill-me\u002FSKILL.md",[447],[494,9996,9997],{},"grill-me"," skill as an example:",[919,10000,10002],{"className":2170,"code":10001,"language":2172,"meta":424,"style":424},"---\nname: grill-me\ndescription: Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to stress-test a plan, get grilled on their design, or mentions \"grill me\".\n---\n\nInterview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer.\n\nAsk the questions one at a time.\n\nIf a question can be answered by exploring the codebase, explore the codebase instead.\n",[494,10003,10004,10009,10019,10029,10033,10037,10042,10046,10051,10055],{"__ignoreMap":424},[927,10005,10006],{"class":929,"line":930},[927,10007,10008],{"class":1036},"---\n",[927,10010,10011,10014,10016],{"class":929,"line":1056},[927,10012,10013],{"class":1328},"name",[927,10015,1253],{"class":941},[927,10017,10018],{"class":1040}," grill-me\n",[927,10020,10021,10024,10026],{"class":929,"line":1063},[927,10022,10023],{"class":1328},"description",[927,10025,1253],{"class":941},[927,10027,10028],{"class":1040}," Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to stress-test a plan, get grilled on their design, or mentions \"grill me\".\n",[927,10030,10031],{"class":929,"line":1070},[927,10032,10008],{"class":1036},[927,10034,10035],{"class":929,"line":1891},[927,10036,1060],{"emptyLinePlaceholder":1059},[927,10038,10039],{"class":929,"line":1896},[927,10040,10041],{"class":1040},"Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer.\n",[927,10043,10044],{"class":929,"line":1902},[927,10045,1060],{"emptyLinePlaceholder":1059},[927,10047,10048],{"class":929,"line":2238},[927,10049,10050],{"class":1040},"Ask the questions one at a time.\n",[927,10052,10053],{"class":929,"line":1667},[927,10054,1060],{"emptyLinePlaceholder":1059},[927,10056,10057],{"class":929,"line":2344},[927,10058,10059],{"class":1040},"If a question can be answered by exploring the codebase, explore the codebase instead.\n",[429,10061,10062,10063,10065],{},"A ",[494,10064,8271],{}," file contains a small block of metadata and a body of instructions. The metadata consists of the skill's name and description, which the AI agent loads at startup.",[473,10067,10069],{"id":10068},"how-ai-agent-skills-work-progressive-disclosure","How AI Agent Skills Work: Progressive Disclosure",[429,10071,10072],{},"Initially, only the name and description are loaded into the context. When a user's request matches a skill's description, the body of instructions is loaded into the same context.",[429,10074,10075,10076,10081],{},"Let's look at how the ",[443,10077,10079],{"href":9993,"rel":10078},[447],[494,10080,9997],{}," skill is used.",[429,10083,10084],{},[432,10085],{"alt":10086,"src":10087},"Sequence diagram illustrating the progressive disclosure mechanism for executing AI agent skills","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FAI%20Agent%20Skills%20What%20They%20Are%20%26%20How%20to%20Create%20Them\u002Fai-agent-skill-progressive-disclosure-sequence-diagram.webp",[874,10089,10091],{"id":10090},"step-by-step","Step-by-Step",[532,10093,10094,10100,10106,10112,10118,10131,10141],{},[487,10095,10096,10099],{},[440,10097,10098],{},"Request"," — The user asks the agent for something (\"grill me on my workflow design\").",[487,10101,10102,10105],{},[440,10103,10104],{},"Selection prompt"," — The user's request, along with the descriptions of all available skills, is sent to the LLM.",[487,10107,10108,10111],{},[440,10109,10110],{},"LLM selects"," — The LLM compares the request to each description and returns the skill(s) that match.",[487,10113,10114,10117],{},[440,10115,10116],{},"Confirmation"," — The agent surfaces the proposed skill(s) back to the user, who confirms (or rejects\u002Fadjusts) the choice.",[487,10119,10120,10123,10124,10127,10128,10130],{},[440,10121,10122],{},"Instructions loaded"," — The agent fetches the ",[894,10125,10126],{},"full"," instructions for the confirmed skill: the ",[494,10129,8271],{}," body.",[487,10132,10133,10136,10137,10140],{},[440,10134,10135],{},"Execution prompt"," — The user's request ",[440,10138,10139],{},"plus the selected skill's instructions"," is sent to the LLM.",[487,10142,10143,10146],{},[440,10144,10145],{},"Response"," — The LLM produces the output, which is the first grilling question.",[429,10148,10149,10150,10157],{},"Now let's use ",[443,10151,10154],{"href":10152,"rel":10153},"https:\u002F\u002Fgithub.com\u002Fcoleam00\u002Fexcalidraw-diagram-skill",[447],[494,10155,10156],{},"excalidraw-diagram-skill"," to illustrate how a skill with a reference document is used:",[429,10159,10160],{},[432,10161],{"alt":10162,"src":10163},"Sequence diagram showing an AI agent executing a skill loaded with external reference files and templates","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FAI%20Agent%20Skills%20What%20They%20Are%20%26%20How%20to%20Create%20Them\u002Fai-agent-skill-with-reference-files-sequence-diagram.webp",[874,10165,10091],{"id":10166},"step-by-step-1",[532,10168,10169,10174,10178,10187,10191,10203,10210],{},[487,10170,10171,10173],{},[440,10172,10098],{}," — The user asks the agent for something (\"draw the workflow of the deployment process\").",[487,10175,10176,10105],{},[440,10177,10104],{},[487,10179,10180,10182,10183,10186],{},[440,10181,10110],{}," — The LLM compares the request to each description and returns the skill(s) that match. Here, \"draw the workflow\" matches the ",[494,10184,10185],{},"excalidraw-diagram"," description, so it is selected.",[487,10188,10189,10117],{},[440,10190,10116],{},[487,10192,10193,10123,10195,10127,10197,10199,10200,10202],{},[440,10194,10122],{},[894,10196,10126],{},[494,10198,8271],{}," body and any referenced files (for ",[494,10201,10185],{},", that includes the colour palette, JSON schema, and element templates).",[487,10204,10205,10136,10207,10209],{},[440,10206,10135],{},[440,10208,10139],{}," is sent to the LLM. The model now has the detailed methodology it needs.",[487,10211,10212,10214,10215,10218],{},[440,10213,10145],{}," — The LLM produces the output (an ",[494,10216,10217],{},".excalidraw"," JSON file), which the agent returns to the user.",[473,10220,10222],{"id":10221},"ai-agent-skills-vs-tools-and-mcp","AI Agent Skills vs. Tools and MCP",[429,10224,10225],{},"Skills don't replace prompts, tools, or MCP. Tools and MCP integrations extend an agent's reach to external systems — querying a database, calling an API, and so on. Skills deepen the agent's know-how for completing a task.",[429,10227,10228,10229,10232],{},"An MCP such as the ",[443,10230,10231],{"href":395},"NetSuite MCP"," lets an agent answer user questions by accessing live financial and operational data in NetSuite. Then a NetSuite operational-reporting skill, in turn, guides the agent on how to compose that report and present the answer as a report to the user.",[429,10234,10235],{},"Some scenarios for using skills include:",[484,10237,10238,10241,10244],{},[487,10239,10240],{},"Multi-step workflows",[487,10242,10243],{},"Processing documents, such as extracting data from PDFs",[487,10245,10246],{},"Code-generation standards",[473,10248,10250],{"id":10249},"how-to-create-ai-agent-skills","How to Create AI Agent Skills",[532,10252,10253,10263,10277,10286],{},[487,10254,10255,10258,10259,10262],{},[440,10256,10257],{},"Create a folder"," named for the skill (e.g. ",[494,10260,10261],{},"netsuite-operation-report\u002F",").",[487,10264,10265,10270,10271,10273,10274,10276],{},[440,10266,10267,10268],{},"Write ",[494,10269,8271],{}," with a ",[494,10272,10013],{},", a sharp ",[494,10275,10023],{},", and a concise body of instructions (under 200 words).",[487,10278,10279,10282,10283,10285],{},[440,10280,10281],{},"Add resources"," the task needs — reference docs, templates, scripts. Keep ",[494,10284,8271],{}," short and link out to the details.",[487,10287,10288,10291,10292,10294],{},[440,10289,10290],{},"Install it"," where agents will discover it. Refer to ",[443,10293,358],{"href":359}," for how to manage skills across multiple agents.",[429,10296,10297],{},"A few tips for writing good skills:",[484,10299,10300,10303,10309,10312],{},[487,10301,10302],{},"Write the description for the trigger, not the human.",[487,10304,10305,10306,10308],{},"Keep ",[494,10307,8271],{}," lean — under 200 words. Put the general case in the body; leave the edge cases to reference documents.",[487,10310,10311],{},"Use scripts for anything deterministic. Don't ask the LLM to do arithmetic.",[487,10313,10314],{},"Version it. Check it into git.",[473,10316,2536],{"id":2535},[429,10318,10319,10320,10323,10324,10327],{},"Unlike tools and MCP, which define ",[894,10321,10322],{},"what to connect to",", agent skills package ",[894,10325,10326],{},"how to do the work",". They are an essential complement, not a replacement.",[429,10329,10330],{},"By leveraging progressive disclosure, skills keep your agent's context window clean and efficient — loading detailed instructions, reference documents, and executable scripts only when a user's request triggers them.",[1611,10332,10333],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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);}",{"title":424,"searchDepth":1056,"depth":1063,"links":10335},[10336,10337,10341,10342,10343],{"id":9976,"depth":1056,"text":9977},{"id":10068,"depth":1056,"text":10069,"children":10338},[10339,10340],{"id":10090,"depth":1063,"text":10091},{"id":10166,"depth":1063,"text":10091},{"id":10221,"depth":1056,"text":10222},{"id":10249,"depth":1056,"text":10250},{"id":2535,"depth":1056,"text":2536},[1631],"2026-06-26","Discover what AI agent skills are, how progressive disclosure works, and learn to build custom reusable skills.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FAI%20Agent%20Skills%20What%20They%20Are%20%26%20How%20to%20Create%20Them\u002FEN-AI-Agent-Skills-What-They-Are-%26-How-to-Create-Them.webp","AI Agent Skills Guide: How to Build Reusable Workflows",{"schemaOrg":10350,"robots":1665,"sitemap":10352},[10351],{"@type":1644,"headline":350,"description":10346},{"lastmod":10345},{"title":10348,"description":10346,"ogTitle":350,"ogDescription":10346,"twitterTitle":350,"twitterDescription":10346},[1672,10355,10356,10357],"Agent Skills","Reusable Workflows","AI Tutorial","KB_UqaFeAxxEkCKJGNsZFWECf41haD9D0uv9jcvrFz8",{"id":10360,"title":374,"author":424,"body":10361,"category":10953,"date":10954,"description":10955,"extension":1636,"image":10956,"imageAlt":10957,"isPublished":1059,"meta":10958,"minRead":1891,"navigation":1059,"path":49,"seo":10972,"stem":376,"tags":10974,"updatedAt":1673,"__hash__":10978},"article\u002Fen\u002Farticle\u002Fhow-to-setup-hermes-on-remote-server.md",{"type":426,"value":10362,"toc":10942},[10363,10367,10370,10373,10377,10381,10384,10397,10403,10406,10431,10438,10465,10472,10477,10491,10503,10509,10514,10530,10534,10537,10556,10562,10565,10576,10586,10597,10628,10632,10642,10651,10661,10671,10678,10688,10694,10721,10737,10741,10747,10759,10764,10798,10802,10805,10819,10825,10888,10890,10934,10936,10939],[473,10364,10366],{"id":10365},"why-host-hermes-agent-on-a-remote-vps","Why Host Hermes Agent on a Remote VPS?",[429,10368,10369],{},"Since the Hermes Agent is capable of running background tasks, scheduling tasks, and responding to webhook calls, we need a machine to be on standby 24\u002F7. Local machines can lose power, get disconnected from Internet or having the resources maxed out. A remote server guarantees 99% uptime and makes it easy to scale computation resources when needed.",[429,10371,10372],{},"There are several affordable virtual private server(VPS)) providers out there such as Hetzner, Hostinger and Contabo. We have been using Contabo for a while, and so far so good.",[473,10374,10376],{"id":10375},"how-to-set-up-hermes-agent-on-a-linux-vps","How to Set Up Hermes Agent on a Linux VPS",[874,10378,10380],{"id":10379},"step-1-connect-to-your-vps","Step 1: Connect to Your VPS",[429,10382,10383],{},"Open the terminal and SSH into your remote machine:",[919,10385,10387],{"className":1027,"code":10386,"language":1029,"meta":424,"style":424},"ssh root@your_server_ip\n",[494,10388,10389],{"__ignoreMap":424},[927,10390,10391,10394],{"class":929,"line":930},[927,10392,10393],{"class":1036},"ssh",[927,10395,10396],{"class":1040}," root@your_server_ip\n",[429,10398,10399],{},[432,10400],{"alt":10401,"src":10402},"SSH connection to the Linux VPS server in terminal","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fvps-terminal-ssh-connection.webp",[429,10404,10405],{},"Ensure your server packages are up to date:",[919,10407,10409],{"className":1027,"code":10408,"language":1029,"meta":424,"style":424},"sudo apt update && sudo apt upgrade -y\n",[494,10410,10411],{"__ignoreMap":424},[927,10412,10413,10415,10417,10420,10422,10424,10426,10429],{"class":929,"line":930},[927,10414,1859],{"class":1036},[927,10416,4431],{"class":1040},[927,10418,10419],{"class":1040}," update",[927,10421,5424],{"class":941},[927,10423,4352],{"class":1036},[927,10425,4431],{"class":1040},[927,10427,10428],{"class":1040}," upgrade",[927,10430,4464],{"class":1040},[429,10432,10433,10434,10437],{},"Add a new user, ",[494,10435,10436],{},"hermes",", or your preferred username:",[919,10439,10441],{"className":1027,"code":10440,"language":1029,"meta":424,"style":424},"sudo adduser hermes \nsudo passwd hermes\n",[494,10442,10443,10455],{"__ignoreMap":424},[927,10444,10445,10447,10450,10453],{"class":929,"line":930},[927,10446,1859],{"class":1036},[927,10448,10449],{"class":1040}," adduser",[927,10451,10452],{"class":1040}," hermes",[927,10454,1992],{"class":937},[927,10456,10457,10459,10462],{"class":929,"line":1056},[927,10458,1859],{"class":1036},[927,10460,10461],{"class":1040}," passwd",[927,10463,10464],{"class":1040}," hermes\n",[429,10466,10467,10468,10471],{},"Turn off ",[494,10469,10470],{},"root"," password login:",[532,10473,10474],{},[487,10475,10476],{},"Open the SSH configuration file:",[919,10478,10480],{"className":1027,"code":10479,"language":1029,"meta":424,"style":424},"sudo nano \u002Fetc\u002Fssh\u002Fsshd_config\n",[494,10481,10482],{"__ignoreMap":424},[927,10483,10484,10486,10488],{"class":929,"line":930},[927,10485,1859],{"class":1036},[927,10487,2278],{"class":1040},[927,10489,10490],{"class":1040}," \u002Fetc\u002Fssh\u002Fsshd_config\n",[532,10492,10493],{"start":1056},[487,10494,10495,10496,10499,10500,1253],{},"Locate the ",[494,10497,10498],{},"PermitRootLogin"," line and change its value to ",[494,10501,10502],{},"no",[919,10504,10507],{"className":10505,"code":10506,"language":4598,"meta":424},[4596],"PermitRootLogin no\n",[494,10508,10506],{"__ignoreMap":424},[532,10510,10511],{"start":1063},[487,10512,10513],{},"Save the file and restart the SSH service:",[919,10515,10517],{"className":1027,"code":10516,"language":1029,"meta":424,"style":424},"sudo systemctl restart ssh\n",[494,10518,10519],{"__ignoreMap":424},[927,10520,10521,10523,10525,10527],{"class":929,"line":930},[927,10522,1859],{"class":1036},[927,10524,1862],{"class":1040},[927,10526,1865],{"class":1040},[927,10528,10529],{"class":1040}," ssh\n",[874,10531,10533],{"id":10532},"step-2-install-hermes-agent","Step 2: Install Hermes Agent",[429,10535,10536],{},"Run the following command:",[919,10538,10540],{"className":1027,"code":10539,"language":1029,"meta":424,"style":424},"curl -fsSL https:\u002F\u002Fhermes-agent.nousresearch.com\u002Finstall.sh | bash\n",[494,10541,10542],{"__ignoreMap":424},[927,10543,10544,10546,10548,10551,10553],{"class":929,"line":930},[927,10545,2950],{"class":1036},[927,10547,4343],{"class":1040},[927,10549,10550],{"class":1040}," https:\u002F\u002Fhermes-agent.nousresearch.com\u002Finstall.sh",[927,10552,4349],{"class":941},[927,10554,10555],{"class":1036}," bash\n",[429,10557,10558],{},[432,10559],{"alt":10560,"src":10561},"Running the Hermes Agent installation script in terminal","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fhermes-agent-installation-terminal.webp",[429,10563,10564],{},"Once installed, verify the installation by typing:",[919,10566,10568],{"className":1027,"code":10567,"language":1029,"meta":424,"style":424},"hermes --version\n",[494,10569,10570],{"__ignoreMap":424},[927,10571,10572,10574],{"class":929,"line":930},[927,10573,10436],{"class":1036},[927,10575,3573],{"class":1040},[429,10577,1798,10578,10581,10582],{},[494,10579,10580],{},"hermes setup"," to configure the Hermes Agent:\n",[432,10583],{"alt":10584,"src":10585},"Running the hermes setup command in terminal to start configuration","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fhermes-agent-setup-wizard.webp",[429,10587,10588,10589,10592,10593],{},"Select an LLM provider, start with ",[494,10590,10591],{},"DeepSeek"," and add others later.\n",[432,10594],{"alt":10595,"src":10596},"Selecting DeepSeek as the LLM provider in Hermes setup","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fhermes-setup-llm-provider-selection.webp",[429,10598,10599,10600,10602,10603,10607,10611,10612,10615,10616,10611,10620,10623,10624],{},"Enter ",[494,10601,10591],{},"API key:\n",[432,10604],{"alt":10605,"src":10606},"Entering the DeepSeek API key in the terminal","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fhermes-setup-enter-api-key.webp",[432,10608],{"alt":10609,"src":10610},"Successful confirmation of the LLM provider API key","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fhermes-setup-api-key-success.webp","\nSelect ",[494,10613,10614],{},"local machine"," for running the Hermes Agent:\n",[432,10617],{"alt":10618,"src":10619},"Selecting local machine for Hermes Agent execution environment","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fhermes-setup-select-local-machine.webp",[494,10621,10622],{},"Telegram"," in the channels. Other channels can be configured later.\n",[432,10625],{"alt":10626,"src":10627},"Selecting Telegram as the communication channel in Hermes setup","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fhermes-setup-select-telegram-channel.webp",[874,10629,10631],{"id":10630},"step-3-integrating-with-telegram","Step 3: Integrating with Telegram",[429,10633,9887,10634,10637,10638],{},[494,10635,10636],{},"[2]"," for using Telegram bot.\n",[432,10639],{"alt":10640,"src":10641},"Selecting option to configure Telegram bot integration","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Ftelegram-bot-integration-option.webp",[429,10643,2133,10644,10646,10647],{},[494,10645,10622],{}," and search for 'BotFather'.\n",[432,10648],{"alt":10649,"src":10650},"Searching for BotFather in the Telegram application","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Ftelegram-search-botfather.webp",[429,10652,4231,10653,10656,10657],{},[494,10654,10655],{},"Open"," to open 'BotFather'.\n",[432,10658],{"alt":10659,"src":10660},"Opening the chat interface with BotFather on Telegram","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Ftelegram-open-botfather-chat.webp",[429,10662,4231,10663,10666,10667],{},[494,10664,10665],{},"Create a New Bot",".\n",[432,10668],{"alt":10669,"src":10670},"Sending newbot command to BotFather to create a new Telegram bot","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fbotfather-create-new-bot.webp",[429,10672,10673,10674],{},"Fill in the names and create the bot.\n",[432,10675],{"alt":10676,"src":10677},"Configuring the name and username for the new Telegram bot","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fbotfather-bot-details-configured.webp",[429,10679,4231,10680,10683,10684],{},[494,10681,10682],{},"Copy"," to copy the token and paste it back to the terminal.\n",[432,10685],{"alt":10686,"src":10687},"Copying the HTTP API token of the newly created Telegram bot","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fbotfather-copy-http-api-token.webp",[429,10689,10690,10691,10693],{},"Find the ",[494,10692,10622],{}," user account ID and add it to the 'Allowed user list':",[484,10695,10696,10705,10718],{},[487,10697,10698,10699,10701],{},"Search '@raw_data_bot' on ",[494,10700,10622],{},[432,10702],{"alt":10703,"src":10704},"Searching for raw data bot on Telegram to retrieve user ID","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Ftelegram-search-raw-data-bot.webp",[487,10706,4217,10707,10710,10711,10666,10714],{},[494,10708,10709],{},"RawDataBot"," then click Start button. The user ID will be shown behind ",[494,10712,10713],{},"P.S. Your ID:",[432,10715],{"alt":10716,"src":10717},"Starting RawDataBot to view the user account ID","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Ftelegram-raw-data-bot-user-id.webp",[487,10719,10720],{},"Copy the user ID and paste to the terminal.",[429,10722,10723,10724,10728,10729,10733],{},"Since we are running on the cloud, we want the service to be started automatically.\n",[432,10725],{"alt":10726,"src":10727},"Configuring the autostart option for Hermes systemd service","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fhermes-setup-autostart-service-option.webp","\nLeave everything as default:\n",[432,10730],{"alt":10731,"src":10732},"Leaving setup configurations as default values in terminal","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fhermes-setup-leave-defaults-1.webp",[432,10734],{"alt":10735,"src":10736},"Completing the default setup options in Hermes configuration","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Fhermes-setup-leave-defaults-2.webp",[473,10738,10740],{"id":10739},"testing-your-hermes-agent-with-telegram-bot","Testing Your Hermes Agent with Telegram Bot",[429,10742,10743,10744,1253],{},"Run the following command to start the ",[494,10745,10746],{},"hermes gateway",[919,10748,10750],{"className":1027,"code":10749,"language":1029,"meta":424,"style":424},"hermes gateway\n",[494,10751,10752],{"__ignoreMap":424},[927,10753,10754,10756],{"class":929,"line":930},[927,10755,10436],{"class":1036},[927,10757,10758],{"class":1040}," gateway\n",[429,10760,2133,10761,10763],{},[494,10762,10622],{}," and add the created bot, '@tech_cloud_hermes_bot', to our chats.",[484,10765,10766,10779,10789],{},[487,10767,10768,10769,10771,10772,10774,10775],{},"type '\u002Fnew' in ",[494,10770,10622],{}," to start a new ",[494,10773,1684],{}," session.\n",[432,10776],{"alt":10777,"src":10778},"Typing new command in Telegram to start a new Hermes Agent session","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Ftelegram-chat-hermes-new-session.webp",[487,10780,10781,10782,10784,10785],{},"type ",[494,10783,1472],{}," will list all available commands.\n",[432,10786],{"alt":10787,"src":10788},"Typing commands in Telegram to view available Hermes instructions","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Ftelegram-chat-hermes-commands-list.webp",[487,10790,10781,10791,10793,10794],{},[494,10792,1502],{}," to see a list of available LLMs.\n",[432,10795],{"alt":10796,"src":10797},"Typing model in Telegram to see the list of active LLMs","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002Ftelegram-chat-hermes-model-selection.webp",[473,10799,10801],{"id":10800},"running-hermes-gateway-as-a-background-service","Running Hermes Gateway as a Background Service",[429,10803,10804],{},"Create service file:",[919,10806,10808],{"className":2267,"code":10807,"language":2269,"meta":424,"style":424},"sudo nano \u002Fetc\u002Fsystemd\u002Fsystem\u002Fhermes-gateway.service\n",[494,10809,10810],{"__ignoreMap":424},[927,10811,10812,10814,10816],{"class":929,"line":930},[927,10813,1859],{"class":1036},[927,10815,2278],{"class":1040},[927,10817,10818],{"class":1040}," \u002Fetc\u002Fsystemd\u002Fsystem\u002Fhermes-gateway.service\n",[429,10820,10821,10822,10824],{},"Paste the following, replace ",[494,10823,10436],{}," in '\u002Fhome\u002Fhermes' with your preferred username:",[919,10826,10828],{"className":2293,"code":10827,"language":2295,"meta":424,"style":424},"[Unit]\nDescription=Hermes Gateway\nAfter=network.target\n\n[Service]\nUser=hermes\nWorkingDirectory=\u002Fhome\u002Fhermes\nExecStart=\u002Fhome\u002Fhermes\u002F.local\u002Fbin\u002Fhermes gateway\nRestart=always\nRestartSec=10\nEnvironment=PATH=\u002Fhome\u002Fhermes\u002F.local\u002Fbin:\u002Fusr\u002Flocal\u002Fbin:\u002Fusr\u002Fbin:\u002Fbin\n\n[Install]\nWantedBy=multi-user.target\n",[494,10829,10830,10834,10839,10843,10847,10851,10855,10859,10864,10868,10872,10876,10880,10884],{"__ignoreMap":424},[927,10831,10832],{"class":929,"line":930},[927,10833,2302],{},[927,10835,10836],{"class":929,"line":1056},[927,10837,10838],{},"Description=Hermes Gateway\n",[927,10840,10841],{"class":929,"line":1063},[927,10842,2312],{},[927,10844,10845],{"class":929,"line":1070},[927,10846,1060],{"emptyLinePlaceholder":1059},[927,10848,10849],{"class":929,"line":1891},[927,10850,2321],{},[927,10852,10853],{"class":929,"line":1896},[927,10854,2326],{},[927,10856,10857],{"class":929,"line":1902},[927,10858,2331],{},[927,10860,10861],{"class":929,"line":2238},[927,10862,10863],{},"ExecStart=\u002Fhome\u002Fhermes\u002F.local\u002Fbin\u002Fhermes gateway\n",[927,10865,10866],{"class":929,"line":1667},[927,10867,2341],{},[927,10869,10870],{"class":929,"line":2344},[927,10871,2347],{},[927,10873,10874],{"class":929,"line":2350},[927,10875,2353],{},[927,10877,10878],{"class":929,"line":2356},[927,10879,1060],{"emptyLinePlaceholder":1059},[927,10881,10882],{"class":929,"line":2361},[927,10883,2364],{},[927,10885,10886],{"class":929,"line":2367},[927,10887,2370],{},[429,10889,2375],{},[919,10891,10893],{"className":2267,"code":10892,"language":2269,"meta":424,"style":424},"sudo systemctl daemon-reload\nsudo systemctl enable hermes-gateway\nsudo systemctl start hermes-gateway\nsudo systemctl status hermes-gateway\n",[494,10894,10895,10903,10914,10924],{"__ignoreMap":424},[927,10896,10897,10899,10901],{"class":929,"line":930},[927,10898,1859],{"class":1036},[927,10900,1862],{"class":1040},[927,10902,2389],{"class":1040},[927,10904,10905,10907,10909,10911],{"class":929,"line":1056},[927,10906,1859],{"class":1036},[927,10908,1862],{"class":1040},[927,10910,1989],{"class":1040},[927,10912,10913],{"class":1040}," hermes-gateway\n",[927,10915,10916,10918,10920,10922],{"class":929,"line":1063},[927,10917,1859],{"class":1036},[927,10919,1862],{"class":1040},[927,10921,2409],{"class":1040},[927,10923,10913],{"class":1040},[927,10925,10926,10928,10930,10932],{"class":929,"line":1070},[927,10927,1859],{"class":1036},[927,10929,1862],{"class":1040},[927,10931,1886],{"class":1040},[927,10933,10913],{"class":1040},[473,10935,2536],{"id":2535},[429,10937,10938],{},"In this article, we focused on how to set up the Hermes Agent and use Telegram to communicate with it. Having the Hermes Agent running on a remote server provides a true digital assistant that runs 24\u002F7.",[1611,10940,10941],{},"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 .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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":424,"searchDepth":1056,"depth":1063,"links":10943},[10944,10945,10950,10951,10952],{"id":10365,"depth":1056,"text":10366},{"id":10375,"depth":1056,"text":10376,"children":10946},[10947,10948,10949],{"id":10379,"depth":1063,"text":10380},{"id":10532,"depth":1063,"text":10533},{"id":10630,"depth":1063,"text":10631},{"id":10739,"depth":1056,"text":10740},{"id":10800,"depth":1056,"text":10801},{"id":2535,"depth":1056,"text":2536},[1631],"2026-06-19","Deploy the Hermes Agent on a remote VPS for 24\u002F7 uptime. Follow our step-by-step guide to integrate it with a custom Telegram bot.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server\u002FHow%20to%20Setup%20Hermes%20on%20Remote%20Server.webp","A step-by-step guide to deploying Hermes Agent on a remote Linux VPS and integrating it with a custom Telegram bot for 24\u002F7 uptime.",{"schemaOrg":10959,"robots":1665,"sitemap":10971},[10960],{"@type":1644,"name":374,"description":10955,"image":10956,"step":10961},[10962,10965,10968],{"@type":1647,"name":10380,"text":10963,"image":10402,"url":10964},"Open the terminal and SSH into your remote machine: Ensure your server packages are up to date: Add a new user, `hermes`, or your preferred usernam...","#step-1-connect-to-your-vps",{"@type":1647,"name":10533,"text":10966,"image":10561,"url":10967},"Run the following command: Once installed, verify the installation by typing: Run `hermes setup` to configure the Hermes Agent: Select an LLM provi...","#step-2-install-hermes-agent",{"@type":1647,"name":10631,"text":10969,"image":10641,"url":10970},"Select `[2]` for using Telegram bot. Head to `Telegram` and search for 'BotFather'. Click `Open` to open 'BotFather'. Click `Create a New Bot`. Fil...","#step-3-integrating-with-telegram",{"lastmod":10954},{"title":10973,"description":10955,"ogTitle":374,"ogDescription":10955,"twitterTitle":374,"twitterDescription":10955},"Hermes Agent VPS Setup: Telegram Bot Integration Guide",[1684,10975,10976,10977,8666],"VPS Setup","Telegram Bot","Linux VPS","gfsduy5l7mhQlgk1B5l15odagbzetTgFxjC5hIpUmKg",{"id":10980,"title":394,"author":1673,"body":10981,"category":11419,"date":11420,"description":11421,"extension":1636,"image":11422,"imageAlt":11423,"isPublished":1059,"meta":11424,"minRead":2238,"navigation":1059,"path":59,"seo":11428,"stem":396,"tags":11430,"updatedAt":1673,"__hash__":11433},"article\u002Fen\u002Farticle\u002Fsetup-netsuite-mcp-on-chatgpt-claude.md",{"type":426,"value":10982,"toc":11405},[10983,10986,11000,11004,11014,11030,11034,11167,11171,11225,11229,11281,11285,11289,11295,11300,11304,11310,11322,11326,11336,11352,11356,11362,11367,11371,11377,11380,11382],[429,10984,10985],{},"Oracle NetSuite has long been a cloud-based enterprise resource planning (ERP) platform for small to medium-sized businesses. However, its website UI is infamous for its steep learning curve, click-heavy navigation, and rigid reporting structures.",[429,10987,10988,10989,10992,10993,574,10996,10999],{},"With the recent release of the ",[440,10990,10991],{},"NetSuite AI Connector Service",", users can leverage the ",[440,10994,10995],{},"Model Context Protocol (MCP)",[440,10997,10998],{},"AI (Artificial Intelligence) Assistants"," to directly ask questions in plain language and get real-time answers from their financial and operational data.",[473,11001,11003],{"id":11002},"how-the-netsuite-mcp-ai-connector-works","How the NetSuite MCP AI Connector Works",[429,11005,11006,11009,11010,11013],{},[440,11007,11008],{},"NetSuite’s MCP"," exposes a suite of tools to the ",[440,11011,11012],{},"AI",", such as running SuiteQL queries, reading Saved Searches and reports, or executing record operations like creating a new customer record. All tools are governed by NetSuite’s native role-based permissions.",[429,11015,11016,11017,11019,11020,11022,11023,11026,11027,11029],{},"When a user asks a question in plain language, the ",[440,11018,11012],{}," uses the ",[440,11021,10995],{}," to translate the request into structured operations that NetSuite understands. ",[440,11024,11025],{},"NetSuite"," executes the operations using the user's permissions, and the results are returned to the ",[440,11028,11012],{}," for analysis and presentation.",[473,11031,11033],{"id":11032},"netsuite-ai-connector-setup-guide","NetSuite AI Connector Setup Guide",[532,11035,11036,11090,11104,11113,11120,11127,11148],{},[487,11037,11038,11039,574,11042,11045],{},"Enable ",[440,11040,11041],{},"Server SuiteScript",[440,11043,11044],{},"REST Web Services",[532,11046,11047,11057,11085],{},[487,11048,11049,11050,10666,11053],{},"Go to ",[894,11051,11052],{},"Setup > Company > Enable Features",[432,11054],{"alt":11055,"src":11056},"Oracle NetSuite Enable Features configuration interface for Company setup","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-setup-company-enable-features.webp",[487,11058,11059,11060,11063,11064],{},"On the ",[440,11061,11062],{},"SuiteCloud"," subtab:\n",[484,11065,11066,11076],{},[487,11067,11068,11069,11071,11072],{},"Under SuiteScript, check the ",[440,11070,11041],{}," box.\n",[432,11073],{"alt":11074,"src":11075},"Enabling Server SuiteScript in NetSuite SuiteCloud tab","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-enable-features-server-suitescript.webp",[487,11077,11078,11079,11071,11081],{},"Under SuiteTalk (Web Services), check the ",[440,11080,11044],{},[432,11082],{"alt":11083,"src":11084},"Enabling REST Web Services in NetSuite SuiteCloud tab","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-enable-features-rest-web-services.webp",[487,11086,11087,11088,460],{},"Click ",[440,11089,6824],{},[487,11091,11092,11093,11096,11097,10666,11100],{},"Install the ",[440,11094,11095],{},"NetSuite MCP Standard Tools"," first. Click on ",[894,11098,11099],{},"Customization > SuiteCloud Development > SuiteApp Marketplace",[432,11101],{"alt":11102,"src":11103},"Navigating to NetSuite SuiteApp Marketplace under Customization","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-suiteapp-marketplace-navigation.webp",[487,11105,11106,11107,10666,11109],{},"Search for ",[440,11108,11095],{},[432,11110],{"alt":11111,"src":11112},"Searching for NetSuite MCP Standard Tools in the marketplace","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-suiteapp-marketplace-search-mcp-tools.webp",[487,11114,11115,11116],{},"Once it is installed, you will see the status 'Installed' on the right.\n",[432,11117],{"alt":11118,"src":11119},"NetSuite MCP Standard Tools displayed as Installed in the marketplace","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-suiteapp-installed-status-mcp-tools.webp",[487,11121,11122,11123],{},"Follow the same instructions to install the 'NetSuite AI Connector Service Companion'.\n",[432,11124],{"alt":11125,"src":11126},"NetSuite AI Connector Service Companion shown as Installed","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-suiteapp-installed-ai-connector-companion.webp",[487,11128,11129,11130],{},"Set up an Integration Record\n",[532,11131,11132,11141],{},[487,11133,11049,11134,10666,11137],{},[894,11135,11136],{},"Setup > Integration > Manage Integrations",[432,11138],{"alt":11139,"src":11140},"Navigating to Manage Integrations in NetSuite Setup menu","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-integration-manage-integrations-navigation.webp",[487,11142,11143,11144],{},"Create an Integration Record for ChatGPT, and we will come back with the actual token_id:\n",[432,11145],{"alt":11146,"src":11147},"Creating a new integration record in NetSuite for ChatGPT","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-create-integration-record-chatgpt.webp",[487,11149,11150,11151,11155,11159,11163],{},"Create a custom role for MCP with the minimum permissions and assign it to users. e.g.,\n",[432,11152],{"alt":11153,"src":11154},"Configuring custom role permissions for NetSuite MCP - Part 1","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-custom-role-mcp-permissions-1.webp",[432,11156],{"alt":11157,"src":11158},"Configuring custom role permissions for NetSuite MCP - Part 2","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-custom-role-mcp-permissions-2.webp",[432,11160],{"alt":11161,"src":11162},"Configuring custom role permissions for NetSuite MCP - Part 3","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-custom-role-mcp-permissions-3.webp",[432,11164],{"alt":11165,"src":11166},"Configuring custom role permissions for NetSuite MCP - Part 4","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-custom-role-mcp-permissions-4.webp",[473,11168,11170],{"id":11169},"how-to-integrate-netsuite-mcp-with-chatgpt","How to Integrate NetSuite MCP with ChatGPT",[532,11172,11173,11180,11187,11194,11204,11211,11218],{},[487,11174,11175,11176],{},"Click on 'Settings'.\n",[432,11177],{"alt":11178,"src":11179},"Navigating to Settings in the ChatGPT user interface","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fchatgpt-settings-navigation.webp",[487,11181,11182,11183],{},"Click on 'Apps' > 'Advanced settings'.\n",[432,11184],{"alt":11185,"src":11186},"Navigating to Apps and Advanced Settings in ChatGPT","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fchatgpt-apps-advanced-settings.webp",[487,11188,11189,11190],{},"Turn on 'Developer mode', then click on 'Create app'.\n",[432,11191],{"alt":11192,"src":11193},"Enabling Developer Mode and clicking Create App in ChatGPT","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fchatgpt-developer-mode-create-app.webp",[487,11195,11196,11197,10666,11200],{},"Enter the details. For Connection, enter ",[494,11198,11199],{},"https:\u002F\u002F\u003Caccount_id>.suitetalk.api.netsuite.com\u002Fservices\u002Fmcp\u002Fv1\u002Fall",[432,11201],{"alt":11202,"src":11203},"Entering NetSuite MCP connection URL details to create app in ChatGPT","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fchatgpt-create-app-netsuite-mcp-connection.webp",[487,11205,11206,11207],{},"Click on 'Create'. Once it is integrated, you will see the following popup.\n",[432,11208],{"alt":11209,"src":11210},"Pop-up confirmation showing NetSuite MCP integrated in ChatGPT","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fchatgpt-netsuite-mcp-integrated-popup.webp",[487,11212,11213,11214],{},"Click on 'Sign in with NetSuite MCP'.\n",[432,11215],{"alt":11216,"src":11217},"ChatGPT prompt to sign in with NetSuite MCP standard tools","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fchatgpt-sign-in-with-netsuite-mcp.webp",[487,11219,11220,11221],{},"Click the 'Continue' button to grant permissions.\n",[432,11222],{"alt":11223,"src":11224},"Granting connection permissions for NetSuite MCP in ChatGPT","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fchatgpt-grant-permissions-netsuite-mcp.webp",[473,11226,11228],{"id":11227},"how-to-integrate-netsuite-mcp-with-claude-ai","How to Integrate NetSuite MCP with Claude AI",[532,11230,11231,11238,11245,11252,11267,11274],{},[487,11232,11233,11234],{},"Click on 'Customize'.\n",[432,11235],{"alt":11236,"src":11237},"Clicking the Customize option in the Claude AI interface","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fclaude-ai-customize-navigation.webp",[487,11239,11240,11241],{},"Click on 'Connect your apps'.\n",[432,11242],{"alt":11243,"src":11244},"Clicking Connect your apps in Claude AI customization settings","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fclaude-ai-connect-your-apps.webp",[487,11246,11247,11248],{},"Search for 'NetSuite'.\n",[432,11249],{"alt":11250,"src":11251},"Searching for the NetSuite application in Claude AI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fclaude-ai-search-netsuite-app.webp",[487,11253,11254,11255,11258,11259,11262,11263],{},"Click on 'NetSuite' and enter the server URL: ",[494,11256,11257],{},"https:\u002F\u002F\u003Caccount_id>.suitetalk.api.netsuite.com\u002Fservices\u002Fmcp\u002Fv1\u002Fsuiteapp\u002Fcom.netsuite.mcpstandardtools",". Replace ",[494,11260,11261],{},"\u003Caccount_id>"," with your actual account ID.\n",[432,11264],{"alt":11265,"src":11266},"Entering NetSuite MCP server connection URL in Claude AI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fclaude-ai-netsuite-mcp-server-url-setup.webp",[487,11268,11269,11270],{},"Click the 'Continue' button.\n",[432,11271],{"alt":11272,"src":11273},"Clicking Continue to authenticate NetSuite MCP server in Claude","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fclaude-ai-netsuite-mcp-continue-authentication.webp",[487,11275,11276,11277],{},"Click 'Continue' to authenticate the connector.\n",[432,11278],{"alt":11279,"src":11280},"Final authentication verification for NetSuite MCP in Claude AI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fclaude-ai-netsuite-mcp-authenticate-connector.webp",[473,11282,11284],{"id":11283},"netsuite-ai-use-cases","NetSuite AI Use Cases",[874,11286,11288],{"id":11287},"use-case-in-chatgpt-show-overdue-invoices-over-30-days-in-netsuite","Use Case in ChatGPT: Show overdue invoices over 30 days in NetSuite",[429,11290,11291],{},[432,11292],{"alt":11293,"src":11294},"ChatGPT running a SuiteQL query to show overdue NetSuite invoices","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fchatgpt-netsuite-overdue-invoices-query-result.webp",[484,11296,11297],{},[487,11298,11299],{},"ChatGPT created the SuiteQL query and ran it. This is very handy and saves a lot of time compared to creating a report using the NetSuite website UI.",[874,11301,11303],{"id":11302},"use-case-in-chatgpt-and-claude-can-you-draw-the-sales-of-the-last-30-days-in-a-line-graph","Use Case in ChatGPT and Claude: Can you draw the sales of the last 30 days in a line graph?",[429,11305,11306],{},[432,11307],{"alt":11308,"src":11309},"ChatGPT failing to render a sales line graph from NetSuite data","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fchatgpt-failed-render-netsuite-sales-line-graph.webp",[484,11311,11312,11315],{},[487,11313,11314],{},"ChatGPT wasn't able to generate the line graph.",[487,11316,11317,11318],{},"I tried on Claude, and it worked. The difference may be due to the large language model capabilities.\n",[432,11319],{"alt":11320,"src":11321},"Claude AI successfully rendering a visual line graph of NetSuite sales","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fclaude-ai-successfully-rendered-netsuite-sales-line-graph.webp",[874,11323,11325],{"id":11324},"use-case-in-claude-create-a-customer-record","Use Case in Claude: Create a customer record",[429,11327,11328,11332],{},[432,11329],{"alt":11330,"src":11331},"Claude AI prompt to create a new customer record in NetSuite","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fclaude-ai-create-netsuite-customer-record-prompt.webp",[432,11333],{"alt":11334,"src":11335},"Claude AI confirmation of successful creation of NetSuite customer record","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fclaude-ai-create-netsuite-customer-record-success.webp",[484,11337,11338,11345],{},[487,11339,11340,11341],{},"Double-checking the NetSuite website UI confirms the record was created.\n",[432,11342],{"alt":11343,"src":11344},"Verifying newly created customer record in NetSuite user interface","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fnetsuite-ui-verify-new-customer-record-created.webp",[487,11346,11347,11348],{},"Running it in ChatGPT shows the record is available:\n",[432,11349],{"alt":11350,"src":11351},"ChatGPT confirming that the new NetSuite customer record is available","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fchatgpt-verify-netsuite-customer-record-available.webp",[874,11353,11355],{"id":11354},"use-case-in-claude-run-suiteql-query","Use Case in Claude: Run SuiteQL Query",[429,11357,11358],{},[432,11359],{"alt":11360,"src":11361},"Claude AI directly executing and displaying results of NetSuite SuiteQL query","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002Fclaude-ai-run-suiteql-query-result.webp",[484,11363,11364],{},[487,11365,11366],{},"The SuiteQL query can be executed directly.",[473,11368,11370],{"id":11369},"final-thoughts-on-the-netsuite-ai-connector","Final Thoughts on the NetSuite AI Connector",[429,11372,11373,11374,11376],{},"The biggest win in using MCP is for users who are not technical enough to create complex reports. These users can use plain language to query the data and ask the ",[440,11375,11012],{}," to present the report exactly the way they want.",[429,11378,11379],{},"To prevent prompt injection attacks and the misuse of 'write' operations, only grant write permissions to certain records and transactions. When the AI uses MCP to update or create a record, it executes this as server-side SuiteScript, which completely bypasses any client-side scripts or form validations.",[473,11381,8017],{"id":6123},[484,11383,11384,11391,11398],{},[487,11385,11386],{},[443,11387,11390],{"href":11388,"rel":11389},"https:\u002F\u002Fdocs.oracle.com\u002Fen\u002Fcloud\u002Fsaas\u002Fnetsuite\u002Fns-online-help\u002Farticle_0902023450.html#subsect_90090238176",[447],"Installing the MCP Standard Tools SuiteApp",[487,11392,11393],{},[443,11394,11397],{"href":11395,"rel":11396},"https:\u002F\u002Fdocs.oracle.com\u002Fen\u002Fcloud\u002Fsaas\u002Fnetsuite\u002Fns-online-help\u002Farticle_4160616848.html#subsect_0419123151",[447],"NetSuite AI Connector Service FAQ",[487,11399,11400],{},[443,11401,11404],{"href":11402,"rel":11403},"https:\u002F\u002Fdocs.oracle.com\u002Fen\u002Fcloud\u002Fsaas\u002Fnetsuite\u002Fns-online-help\u002Fsection_0714082142.html#bridgehead_0804033331",[447],"Connect to the NetSuite AI Connector Service",{"title":424,"searchDepth":1056,"depth":1063,"links":11406},[11407,11408,11409,11410,11411,11417,11418],{"id":11002,"depth":1056,"text":11003},{"id":11032,"depth":1056,"text":11033},{"id":11169,"depth":1056,"text":11170},{"id":11227,"depth":1056,"text":11228},{"id":11283,"depth":1056,"text":11284,"children":11412},[11413,11414,11415,11416],{"id":11287,"depth":1063,"text":11288},{"id":11302,"depth":1063,"text":11303},{"id":11324,"depth":1063,"text":11325},{"id":11354,"depth":1063,"text":11355},{"id":11369,"depth":1056,"text":11370},{"id":6123,"depth":1056,"text":8017},[1631],"2026-06-13","Set up the NetSuite AI Connector (MCP) with ChatGPT and Claude. Discover how to query ERP data and automate tasks using plain language AI.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20NetSuite%20MCP%20on%20ChatGPT%20%26%20Claude\u002FEN-Setup-NetSuite-MCP-on-ChatGPT-%26-Claude.webp","NetSuite MCP AI Integration thumbnail featuring dark blue corporate background with ChatGPT and Claude logos connected to NetSuite cloud database",{"schemaOrg":11425,"robots":1665,"sitemap":11427},[11426],{"@type":1642,"headline":394,"description":11421},{"lastmod":11420},{"title":11429,"description":11421,"ogTitle":394,"ogDescription":11421,"twitterTitle":394,"twitterDescription":11421},"NetSuite MCP AI Integration: Connect ChatGPT & Claude",[11025,6904,11431,11432,11012],"ChatGPT","Claude","n1J7EtXz8z5uvCvRLH2MOq2iyQH1APdphDzNPW84yaE",{"id":11435,"title":406,"author":1673,"body":11436,"category":11628,"date":11629,"description":11630,"extension":1636,"image":11631,"imageAlt":11632,"isPublished":1059,"meta":11633,"minRead":1891,"navigation":1059,"path":65,"seo":11637,"stem":408,"tags":11638,"updatedAt":1673,"__hash__":11642},"article\u002Fen\u002Farticle\u002Ftesting-claude-fable-5-in-financial-analysis.md",{"type":426,"value":11437,"toc":11626},[11438,11449,11460,11463,11469,11485,11495,11501,11507,11513,11535,11544,11558,11566,11584,11587,11598,11607,11610,11623],[429,11439,11440,11441,11444,11445],{},"On June 9, 2026, Anthropic released ",[440,11442,11443],{},"Claude Fable 5",", a Mythos-Class model with advanced safeguards in some areas such as cybersecurity, distillation, chemistry and biology.\n",[432,11446],{"alt":11447,"src":11448},"Anthropic Claude Fable 5 launch announcement and model capabilities","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fclaude-fable-5-launch-announcement.webp",[429,11450,11451,11452,11455,11456],{},"Anthropic has published numbers showing Fable 5 is ahead of Opus 4.8 and GPT-5.5 on several key benchmarks. In ",[440,11453,11454],{},"GDPval-AA (knowledge work)",", it is significantly ahead of Opus 4.8, GPT 5.5 and Gemini 3.1 Pro.\n",[432,11457],{"alt":11458,"src":11459},"Claude Fable 5 benchmark comparison including GDPval-AA knowledge work score","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fclaude-fable-5-benchmarks-gdpval-aa.webp",[429,11461,11462],{},"According to Claude, \"Fable 5 shows strong performance on complex analytical tasks.\".",[429,11464,11465],{},[432,11466],{"alt":11467,"src":11468},"Claude Fable 5 performance statement on complex analytical tasks","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fclaude-fable-5-analytical-performance-statement.webp",[429,11470,11471,11472,11475,11476,11479,11480,460],{},"We decided to test ",[440,11473,11474],{},"Fable 5"," by running an analysis of 'Space Exploration Technologies Corporation(SpaceX)' for investment research purposes, using the '",[440,11477,11478],{},"comps-analysis","' skill. The 'skill.md' file was from ",[443,11481,11484],{"href":11482,"rel":11483},"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Ffinancial-services\u002Fblob\u002Fmain\u002Fplugins\u002Fagent-plugins\u002Fmarket-researcher\u002Fskills\u002Fcomps-analysis\u002FSKILL.md",[447],"Anthropic's financial-services GitHub repository",[429,11486,11487,11491],{},[432,11488],{"alt":11489,"src":11490},"Initiating SpaceX financial comps analysis skill in Claude chat","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fspacex-comps-analysis-skill-initiation.webp",[432,11492],{"alt":11493,"src":11494},"Claude Fable 5 executing automated financial comps analysis for SpaceX","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fspacex-comps-analysis-running-progress.webp",[429,11496,11497],{},[432,11498],{"alt":11499,"src":11500},"SpaceX automated financial comps analysis workflow final output","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fspacex-comps-analysis-skill-results-terminal.webp",[429,11502,11503,11504,11506],{},"The task took around 25 mins. Claude did not ask any clarifying questions except to request permission to access external websites. Impressively, ",[440,11505,11474],{}," was capable of finding the peer companies for comparison.",[429,11508,11509],{},[432,11510],{"alt":11511,"src":11512},"Claude Fable 5 requesting explicit permission for external website access","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fclaude-fable-5-external-site-access-permission.webp",[429,11514,11515,11519,11520,11523,11524,11529,11530,460],{},[432,11516],{"alt":11517,"src":11518},"SpaceX peer group companies identified autonomously by Claude Fable 5","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fclaude-fable-5-spacex-comps-excel-memo.webp","\n*",[440,11521,11522],{},"Please note:"," This is for research and educational purpose and does not constitute investment advice. Original generated files can be downloaded here, ",[443,11525,11528],{"href":11526,"rel":11527},"https:\u002F\u002Ftechvoyage.dev\u002FSpaceX_Comps_Analysis_2026-06-10.xlsx",[447],"SpaceX_Comps_Analysis_2026-06-10.xlsx",", and, ",[443,11531,11534],{"href":11532,"rel":11533},"https:\u002F\u002Ftechvoyage.dev\u002FSpaceX_Comps_Memo_2026-06-10.pdf",[447],"SpaceX_Comps_Memo_2026-06-10.pdf",[429,11536,11537,11538,11541,11542,460],{},"When we tested the same skill using ",[440,11539,11540],{},"Qwen deep research",", we had to manually enter the peer companies. The numerical figures are differed slightly compared to ",[440,11543,11474],{},[429,11545,11546,11550,11554],{},[432,11547],{"alt":11548,"src":11549},"Initiating SpaceX investment comps analysis in Qwen deep research","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fqwen-deep-research-spacex-comps-initiation.webp",[432,11551],{"alt":11552,"src":11553},"Entering peer companies manually in Qwen deep research for SpaceX analysis","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fqwen-deep-research-spacex-comps-running.webp",[432,11555],{"alt":11556,"src":11557},"SpaceX financial benchmark analysis report preview generated by Qwen","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fqwen-deep-research-spacex-comps-report-preview.webp",[429,11559,11560,11561,460],{},"*The Qwen-generated report can be downloaded here, ",[443,11562,11565],{"href":11563,"rel":11564},"https:\u002F\u002Ftechvoyage.dev\u002FThe_SpaceX_Comp_Analysis_A_Statistical_Benchmark_of_Growth_Efficiency_and_Valuation_Against_Public_Peers.pdf",[447],"The_SpaceX_Comp_Analysis_A_Statistical_Benchmark_of_Growth_Efficiency_and_Valuation_Against_Public_Peers.pdf",[429,11567,11568,11569,11572,11573,10666,11576,11580],{},"Although both reports from Claude and Qwen were produced based on the same methodology specified in the skill, the numbers varied because Claude and Qwen pulled from different sources. For example, Claude Fable 5 used ",[440,11570,11571],{},"Stock Analysis"," while Qwen used ",[440,11574,11575],{},"SEC.gov",[432,11577],{"alt":11578,"src":11579},"Financial data extracted from Stock Analysis by Claude Fable 5","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fclaude-fable-5-data-source-stock-analysis.webp",[432,11581],{"alt":11582,"src":11583},"SEC filings and SEC.gov data source utilized by Qwen deep research","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fqwen-deep-research-data-source-sec-gov.webp",[429,11585,11586],{},"The report from Qwen also contained much more information regarding the business model, capital structure and operation.",[429,11588,11589,11590,11593,11594],{},"After comparing reports, we have decided to try again with ",[494,11591,11592],{},"\u002Fresearch"," command in Claude desktop app.\n",[432,11595],{"alt":11596,"src":11597},"Using the new research command in Claude desktop app for company analysis","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fclaude-desktop-research-command-spacex.webp",[429,11599,11600,11601,11606],{},"The newly generated analysis report, ",[443,11602,11605],{"href":11603,"rel":11604},"https:\u002F\u002Ftechvoyage.dev\u002FSpaceX_Analysis.pdf",[447],"SpaceX_Analysis.pdf",", included extra recommendations and caveats sections. Compared to Qwen deep search, it still lacked detailed company information such as operation and capital structure.",[429,11608,11609],{},"Is Fable 5 worth the premium price tag?  It might be for hard, long tasks and autonomous coding. But for certain knowledge work, like company analysis, it may not be the best value yet.",[429,11611,11612,11613,11615,11616,10666,11619],{},"At then end,  we tested how well ",[440,11614,11474],{}," performs in translation. Strangely, the model auto switched back to ",[440,11617,11618],{},"Opus 4.8",[432,11620],{"alt":11621,"src":11622},"Claude desktop app automatically switching model from Fable 5 to Opus 4.8","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002Fclaude-fable-5-translation-opus-switching.webp",[429,11624,11625],{},"Does this mean any long-context conversion will be reverted back to Opus 4.8 ? Is this just a temporary quirk during the usage before 22nd June? Or is the system simply smart enough to tell the translation doesn't require such a powerful model.",{"title":424,"searchDepth":1056,"depth":1063,"links":11627},[],[1631],"2026-06-11","We test Anthropic's new Claude Fable 5 against Qwen Deep Research for financial analysis. Is it worth the upgrade?","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FTesting%20Claude%20Fable%205%20in%20Financial%20Analysis\u002FEN-Testing-Claude-Fable-5-in-Financial-Analysis.webp","Claude Fable 5 vs. Qwen: AI Financial Analysis Test",{"schemaOrg":11634,"robots":1665,"sitemap":11636},[11635],{"@type":1642,"headline":406,"description":11630},{"lastmod":11629},{"title":11632,"description":11630,"ogTitle":406,"ogDescription":11630,"twitterTitle":406,"twitterDescription":11630},[11443,11639,11640,11641],"Financial Analysis","Qwen Deep Research","AI Benchmarks","J6NVfbKL1YA1E1Tc1TMJkxuXDiByHJMBMjIpwWtaYTg",{"id":11644,"title":410,"author":1673,"body":11645,"category":11852,"date":11853,"description":11854,"extension":1636,"image":11855,"imageAlt":11856,"isPublished":1059,"meta":11857,"minRead":1891,"navigation":1059,"path":67,"seo":11861,"stem":412,"tags":11862,"updatedAt":1673,"__hash__":11863},"article\u002Fen\u002Farticle\u002Fuse-browser-and-scheduler-in-antigravity-2.md",{"type":426,"value":11646,"toc":11847},[11647,11660,11664,11669,11678,11693,11699,11702,11713,11717,11720,11727,11734,11745,11748,11754,11765,11771,11781,11794,11804,11814,11817,11823,11826,11837],[429,11648,597,11649,574,11652,11655,11656,11659],{},[494,11650,11651],{},"\u002Fbrowser",[494,11653,11654],{},"\u002Fschedule"," commands in ",[440,11657,11658],{},"Google Antigravity 2"," redefine how we interact with AI. These two commands transform Antigravity into a proactive automation platform that can interact with the live web and run recurring workflows.",[473,11661,11663],{"id":11662},"browser-run","Browser Run",[429,11665,597,11666,11668],{},[494,11667,11651],{}," command forces the use of the Chrome browser to complete a task. Users remain in control over when and how agents access the web during the workflow. Screenshots and video clips are taken during the process.",[429,11670,11671,11674],{},[440,11672,11673],{},"Use Case:",[432,11675],{"alt":11676,"src":11677},"Using the \u002Fbrowser command to submit sick leave","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fbrowser-command-sick-leave-prompt.webp",[429,11679,11680,11681,11685,11689],{},"The following are the output from the agent:\n",[432,11682],{"alt":11683,"src":11684},"Browser automation subagent starting the sick leave submission task","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fbrowser-automation-subagent-delegation.webp",[432,11686],{"alt":11687,"src":11688},"Browser automator setting up Chrome with remote debugging and permissions","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fbrowser-automation-permissions-and-chrome-setup.webp",[432,11690],{"alt":11691,"src":11692},"Browser subagent pausing at a login wall requesting user credentials","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fbrowser-automation-login-wall-encountered.webp",[429,11694,11695],{},[432,11696],{"alt":11697,"src":11698},"Browser subagent waiting for the user to complete the login process","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fbrowser-automation-waiting-for-user-login.webp",[429,11700,11701],{},"Antigravity was capable of opening the page and submitting the form. When a login is required, the agent will wait until you have logged in to the website.",[429,11703,11704,11709,11710,11712],{},[11705,11706],"video",{"alt":11707,"src":11708,"controls":1059},"Video of the browser subagent executing the sick leave submission process","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fbrowser-automation-sick-leave-process.webm","\nThe ",[494,11711,11651],{}," command is useful when we need the most recent documentation from the web, change logs, testing web applications, or checking API statuses to complete a task.",[473,11714,11716],{"id":11715},"schedule-task","Schedule Task",[429,11718,11719],{},"Antigravity 2 has built-in functionality for scheduling tasks. We will test it out by auto-entering a timesheet every 10 minutes.",[429,11721,11722,11723],{},"Click on 'Scheduled Tasks':\n",[432,11724],{"alt":11725,"src":11726},"Scheduled Tasks menu option in the sidebar","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fscheduled-tasks-menu-item.webp",[429,11728,11729,11730],{},"Click on '+ New' button to create a new scheduled task:\n",[432,11731],{"alt":11732,"src":11733},"Empty Scheduled Tasks view with a new task button","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fscheduled-tasks-empty-state-new-button.webp",[429,11735,11736,11737,11741],{},"Fill in the form and schedule the task to run every 10 minutes:\n",[432,11738],{"alt":11739,"src":11740},"New Scheduled Task form filled out for auto timesheet entry","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fscheduled-tasks-new-task-form.webp",[432,11742],{"alt":11743,"src":11744},"Active Auto Timesheet Entry task in the Scheduled Tasks list","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fscheduled-tasks-active-task-list.webp",[429,11746,11747],{},"The task was triggered, but it resulted in an error.",[429,11749,11750],{},[432,11751],{"alt":11752,"src":11753},"Error message indicating no available models found for tier flash","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fscheduled-tasks-error-no-models.webp",[429,11755,11756,11757,11760,11761,11764],{},"We tried adding 'env' values to the ",[494,11758,11759],{},"sidecar.json"," file, which is located at ",[494,11762,11763],{},".gemini\u002Fconfig\u002Fsidecars\u002Fauto-timesheet-entry",", but we still received the same error.",[919,11766,11769],{"className":11767,"code":11768,"language":4598},[4596],"    \"env\": {\n        \"GEMINI_MODEL\": \"gemini-3.5-flash\",\n        \"GOOGLE_CLOUD_PROJECT\": \"your-gcp-project-id\"\n    }\n",[494,11770,11768],{"__ignoreMap":424},[429,11772,11773,11774,11777,11778,460],{},"Inspecting the scheduled task logs located at ",[494,11775,11776],{},".gemini\u002Fantigravity\u002Fsidecar_data\u002F",", we can see ",[494,11779,11780],{},"[schedule] Triggering command: \"agentapi\" [new-conversation]",[429,11782,11783,11784,11789,11790,11793],{},"The response to our issue posted in the ",[443,11785,11788],{"href":11786,"rel":11787},"https:\u002F\u002Fdiscuss.ai.google.dev\u002Ft\u002Fscheduled-tasks-in-antigravity-2-ended-with-errors\u002F168013",[447],"Build with Google AI Forum"," suggests an API key is required for ",[494,11791,11792],{},"agentapi",". We tried using the API key, but still had no luck.",[429,11795,11796,11797,11799,11800],{},"We tried again with the command, ",[494,11798,11654],{},", directly in the conversation box.\n",[432,11801],{"alt":11802,"src":11803},"Using the \u002Fschedule command to prompt the timesheet automation task","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fschedule-command-timesheet-prompt.webp",[429,11805,11806,11807,11809,11810],{},"Tasks scheduled using the ",[494,11808,11654],{}," command will not appear under the 'Scheduled Tasks' menu item.\n",[432,11811],{"alt":11812,"src":11813},"Scheduled Tasks list not showing tasks created via CLI command","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fscheduled-tasks-list-missing-cli-task.webp",[429,11815,11816],{},"The cron task did get triggered.",[429,11818,11819],{},[432,11820],{"alt":11821,"src":11822},"Cron job log confirming it was triggered","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002Fcron-job-triggered-log.webp",[473,11824,11825],{"id":7998},"Final thoughts",[429,11827,597,11828,11830,11831,11833,11834,11836],{},[494,11829,11651],{},"and ",[494,11832,11654],{}," commands in Antigravity 2 are not just isolated features, combining them creates a powerful tool. For example, scheduling an agent to use ",[494,11835,11651],{}," to navigate to news and information websites every Monday morning at 6:00 AM, synthesise the info, and deliver a comprehensive daily briefing.",[429,11838,11839,11840,11843,11844,11846],{},"Other commands, such as ",[494,11841,11842],{},"\u002Fgrill-me"," (mentioned in the article ",[443,11845,418],{"href":419},"), can be used when designing new scheduled tasks. It prompts the agent to ask users to clarify ambiguities and catch edge cases before finalising the design.",{"title":424,"searchDepth":1056,"depth":1063,"links":11848},[11849,11850,11851],{"id":11662,"depth":1056,"text":11663},{"id":11715,"depth":1056,"text":11716},{"id":7998,"depth":1056,"text":11825},[1631],"2026-06-07","Discover how the \u002Fbrowser and \u002Fschedule commands elevate Google Antigravity 2 into a powerful AI automation platform.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FUse%20Browser%20and%20Scheduler%20in%20Antigravity%202\u002FEN-Use-Browser-and-Scheduler-in-Antigravity-2.webp","Google Antigravity 2: Browser & Schedule Automation",{"schemaOrg":11858,"robots":1665,"sitemap":11860},[11859],{"@type":1642,"headline":11856,"description":11854},{"lastmod":11853},{"title":11856,"description":11854,"ogTitle":410,"ogDescription":11854,"twitterTitle":410,"twitterDescription":11854},[],"wBPCXqVDTvGjZ5P0r2QIrZ_gxJDBEG-f-WRL-9uORhQ",{"id":11865,"title":418,"author":424,"body":11866,"category":12187,"date":12188,"description":12189,"extension":1636,"image":12190,"imageAlt":12191,"isPublished":1059,"meta":12192,"minRead":1891,"navigation":1059,"path":71,"seo":12196,"stem":420,"tags":12197,"updatedAt":1673,"__hash__":12198},"article\u002Fen\u002Farticle\u002Fwhat-can-we-do-with-antigravity-2.md",{"type":426,"value":11867,"toc":12177},[11868,11871,11877,11881,11887,11890,11894,11900,11903,11909,11915,11921,11931,11936,11940,11948,11952,11958,11964,11970,11973,11979,11985,11990,11995,11998,12002,12010,12016,12020,12026,12032,12038,12041,12045,12048,12052,12058,12064,12070,12073,12153,12159,12169,12171,12174],[429,11869,11870],{},"Antigravity 2, as an agent-first desktop application, allows users to orchestrate a team of subagents to generate a daily brief from emails and calendars, or to build, test, and deploy an application. But what does this actually look like in practice?",[429,11872,11873,11874,11876],{},"Let’s explore what Antigravity 2 can do for you—from built-in commands and skills to how integrations like Firebase Model Context Protocol (MCP) servers are turning developers into full-stack architects. Please refer to this article, ",[443,11875,390],{"href":391},", for setting up and configuring skills and MCP servers.",[473,11878,11880],{"id":11879},"built-in-commands","Built-in Commands",[874,11882,11884],{"id":11883},"goal",[494,11885,11886],{},"\u002Fgoal",[429,11888,11889],{},"With this command, you tell the agent to run until a specific task is completely finished.",[429,11891,11892],{},[440,11893,11673],{},[429,11895,11896],{},[432,11897],{"alt":11898,"src":11899},"Prompting the Antigravity 2 goal command to build a Textris game","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-goal-command-prompt.webp",[429,11901,11902],{},"When we ask for dynamic subagents, three agents are spawned to complete the task.",[429,11904,11905],{},[432,11906],{"alt":11907,"src":11908},"Antigravity 2 spawning subagents to complete tasks autonomously","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-spawning-subagents-1.webp",[429,11910,11911],{},[432,11912],{"alt":11913,"src":11914},"Detailed progress of Antigravity 2 subagents executing steps","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-spawning-subagents-2.webp",[429,11916,11917],{},[432,11918],{"alt":11919,"src":11920},"Completion of autonomous tasks by Antigravity 2 subagents","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-spawning-subagents-3.webp",[429,11922,11923,11924,1342,11927],{},"To play the generated Textris game in HTML, please click this ",[443,11925,6850],{"href":11926},"\u002Ftextris",[11705,11928],{"alt":11929,"src":11930,"controls":1059},"AI generated Textris game in HTML","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fai-generated-textri-game-html.webm",[429,11932,597,11933,11935],{},[494,11934,11886],{}," command creates a plan, executes it step by step, and reports the progress to you at each stage. Additionally, the agent will manage the context window itself without exceeding limits. This is suitable for lengthy tasks, such as performance optimisation or module refactoring, which require multiple rounds of iteration.",[874,11937,11938],{"id":9997},[494,11939,11842],{},[429,11941,11942,11943,11947],{},"This command triggers the skill ",[443,11944,9997],{"href":11945,"rel":11946},"https:\u002F\u002Fgithub.com\u002Fmattpocock\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fproductivity\u002Fgrill-me\u002FSKILL.md",[447],", created by Matt Pocock. It is concise and highly effective. The idea behind it is to question you from multiple aspects, clarify edge cases, align the structures, and finalise the plan before implementation.",[429,11949,11950],{},[440,11951,11673],{},[429,11953,11954],{},[432,11955],{"alt":11956,"src":11957},"Triggering the grill-me command for Cloudflare architecture in Antigravity 2","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-grill-me-command-prompt.webp",[429,11959,11960],{},[432,11961],{"alt":11962,"src":11963},"Interactive questioning session using the grill-me skill","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-grill-me-interaction-1.webp",[429,11965,11966],{},[432,11967],{"alt":11968,"src":11969},"Clarifying edge cases and structuring the plan with grill-me","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-grill-me-interaction-2.webp",[429,11971,11972],{},"It supports multi-select capabilities:",[429,11974,11975],{},[432,11976],{"alt":11977,"src":11978},"Using multi-select capabilities during the grill-me process","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-grill-me-multi-select-1.webp",[429,11980,11981],{},[432,11982],{"alt":11983,"src":11984},"Finalizing choices with the grill-me multi-select feature","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-grill-me-multi-select-2.webp",[429,11986,597,11987,11989],{},[494,11988,11842],{}," command is quite impressive. It covers almost all aspects of architectural design for deploying to Cloudflare. This makes it suitable for the architectural design of an app, refactoring across multiple domains, and other potentially complex tasks.",[874,11991,11992],{"id":424},[494,11993,11994],{},"@\u002F ",[429,11996,11997],{},"This command doesn't appear on the available list, but we sometimes need it for our context window. It is used to add a folder or files (other than media) to the conversation box.",[473,11999,12001],{"id":12000},"skills","Skills",[429,12003,12004,12005,12007,12008,460],{},"We can type ",[494,12006,8356],{}," to activate the popup box and select a skill. Let's test out ",[494,12009,10185],{},[429,12011,12012],{},[432,12013],{"alt":12014,"src":12015},"Selecting the Excalidraw diagram skill from the Antigravity popup box","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-skill-selection-excalidraw.webp",[429,12017,12018],{},[440,12019,11673],{},[429,12021,12022],{},[432,12023],{"alt":12024,"src":12025},"Providing instructions to generate an Excalidraw diagram","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-excalidraw-diagram-prompt.webp",[429,12027,12028],{},[432,12029],{"alt":12030,"src":12031},"Successful generation of an Excalidraw architecture diagram","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-excalidraw-diagram-generation.webp",[429,12033,12034],{},[432,12035],{"alt":12036,"src":12037},"Antigravity architecture diagram","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-architecture.webp",[429,12039,12040],{},"The skill was successfully executed after a couple of rounds of permission confirmations.",[473,12042,12044],{"id":12043},"mcp-servers","MCP Servers",[429,12046,12047],{},"When the agent builds a backend, you usually have to open a web console, create a database, copy API keys, and paste them back. By leveraging MCP servers directly in Antigravity, the agent gains \"hands\" to manipulate your cloud infrastructure.",[429,12049,12050],{},[440,12051,11673],{},[429,12053,12054],{},[432,12055],{"alt":12056,"src":12057},"Instructing the MCP server to create a Firebase web application","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-mcp-server-firebase-prompt.webp",[429,12059,12060],{},[432,12061],{"alt":12062,"src":12063},"Antigravity using MCP servers to manipulate Firebase infrastructure","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-mcp-server-firebase-execution-1.webp",[429,12065,12066],{},[432,12067],{"alt":12068,"src":12069},"Successful creation of a Firebase app via Antigravity MCP servers","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-mcp-server-firebase-execution-2.webp",[429,12071,12072],{},"The agent successfully managed to create the web app in Firebase using MCP servers. Let's check the repository.",[919,12074,12076],{"className":1027,"code":12075,"language":1029,"meta":424,"style":424},"Create a new public GitHub repository called ‘to-do-app-techvoyage’. Then push all the current project files to it with the commit message ‘Initial commit — to-do-app’.\n",[494,12077,12078],{"__ignoreMap":424},[927,12079,12080,12083,12086,12089,12092,12095,12098,12101,12104,12107,12110,12113,12116,12119,12122,12125,12128,12131,12134,12136,12139,12142,12145,12147,12150],{"class":929,"line":930},[927,12081,12082],{"class":1036},"Create",[927,12084,12085],{"class":1040}," a",[927,12087,12088],{"class":1040}," new",[927,12090,12091],{"class":1040}," public",[927,12093,12094],{"class":1040}," GitHub",[927,12096,12097],{"class":1040}," repository",[927,12099,12100],{"class":1040}," called",[927,12102,12103],{"class":1040}," ‘to-do-app-techvoyage’.",[927,12105,12106],{"class":1040}," Then",[927,12108,12109],{"class":1040}," push",[927,12111,12112],{"class":1040}," all",[927,12114,12115],{"class":1040}," the",[927,12117,12118],{"class":1040}," current",[927,12120,12121],{"class":1040}," project",[927,12123,12124],{"class":1040}," files",[927,12126,12127],{"class":1040}," to",[927,12129,12130],{"class":1040}," it",[927,12132,12133],{"class":1040}," with",[927,12135,12115],{"class":1040},[927,12137,12138],{"class":1040}," commit",[927,12140,12141],{"class":1040}," message",[927,12143,12144],{"class":1040}," ‘Initial",[927,12146,12138],{"class":1040},[927,12148,12149],{"class":1040}," —",[927,12151,12152],{"class":1040}," to-do-app’.\n",[429,12154,12155],{},[432,12156],{"alt":12157,"src":12158},"Agent automatically pushing project files to a new GitHub repository","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002Fantigravity-github-repository-push.webp",[429,12160,597,12161,12164,12165,460],{},[494,12162,12163],{},"to-do-app-techvoyage"," repository is available on GitHub via this ",[443,12166,6850],{"href":12167,"rel":12168},"https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fto-do-app-techvoyage",[447],[473,12170,7999],{"id":7998},[429,12172,12173],{},"While MCP and Skills in Antigravity 2—powered by Gemini 3.5 Flash—deliver blazing speed, the agentic flow is currently bottlenecked by constant permission interruptions and a lack of checkpoints for rollbacks. Until the checkpoint feature is introduced, frequent Git commits are your mandatory safety net.",[1611,12175,12176],{},"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 .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":1056,"depth":1063,"links":12178},[12179,12184,12185,12186],{"id":11879,"depth":1056,"text":11880,"children":12180},[12181,12182,12183],{"id":11883,"depth":1063,"text":11886},{"id":9997,"depth":1063,"text":11842},{"id":424,"depth":1063,"text":11994},{"id":12000,"depth":1056,"text":12001},{"id":12043,"depth":1056,"text":12044},{"id":7998,"depth":1056,"text":7999},[1631],"2026-06-06","Explore Antigravity 2, an agent-first desktop app. Learn to orchestrate AI subagents, use built-in skills, and leverage MCP servers to build full-stack apps.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FWhat%20can%20we%20do%20with%20Antigravity%202\u002FEN-What-can-we-do-with-Antigravity-2.webp","Antigravity 2 Tutorial: AI Agents, Skills & MCP Servers",{"schemaOrg":12193,"robots":1665,"sitemap":12195},[12194],{"@type":1642,"headline":418,"description":12189},{"lastmod":12188},{"title":12191,"description":12189,"ogTitle":418,"ogDescription":12189,"twitterTitle":418,"twitterDescription":12189},[],"U_t3QHoisc4J0w2_q_UUlQYV9k1Tp7YZnz98IAWkOWA",{"id":12200,"title":390,"author":1673,"body":12201,"category":12880,"date":12881,"description":12882,"extension":1636,"image":12883,"imageAlt":12884,"isPublished":1059,"meta":12885,"minRead":1070,"navigation":1059,"path":57,"seo":12889,"stem":392,"tags":12890,"updatedAt":1673,"__hash__":12891},"article\u002Fen\u002Farticle\u002Fsetup-antigravity-2.md",{"type":426,"value":12202,"toc":12869},[12203,12214,12216,12219,12230,12233,12237,12246,12252,12259,12265,12272,12282,12284,12288,12295,12301,12304,12310,12314,12317,12329,12343,12350,12362,12372,12386,12388,12392,12395,12408,12411,12716,12726,12732,12742,12748,12754,12760,12762,12766,12776,12788,12794,12800,12806,12823,12826,12832,12834,12838,12841,12847,12850,12856,12858,12860,12863,12866],[429,12204,12205,12206,12209,12210,12213],{},"At Google I\u002FO 2026, Google announced ",[440,12207,12208],{},"Antigravity 2",", a standalone desktop application that treats the ",[440,12211,12212],{},"agent"," as the primary user interface. You simply describe what you want to achieve, and the agent will then generate a plan, break it down into manageable subtasks, and execute them.",[874,12215,1724],{"id":1723},[429,12217,12218],{},"Before we begin, you will need:",[484,12220,12221,12224,12227],{},[487,12222,12223],{},"A computer (macOS is used in this guide)",[487,12225,12226],{},"A modern web browser",[487,12228,12229],{},"A Gmail account",[12231,12232],"hr",{},[473,12234,12236],{"id":12235},"_1-install-antigravity-2","1. Install Antigravity 2",[429,12238,12239,12240,12245],{},"Download Antigravity 2 from ",[443,12241,12244],{"href":12242,"rel":12243},"https:\u002F\u002Fantigravity.google\u002Fdownload",[447],"antigravity.google"," and install it on your computer. On the first launch, you will be prompted to sign in using your Gmail account.",[429,12247,12248],{},[432,12249],{"alt":12250,"src":12251},"Google account login screen for Antigravity 2 first launch","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-gmail-login.webp",[429,12253,12254,12255,12258],{},"Once signed in, you will notice a ",[440,12256,12257],{},"voice button"," in the input field, allowing you to record voice prompts instead of typing them.",[429,12260,12261],{},[432,12262],{"alt":12263,"src":12264},"Voice dictation and prompt recording button in Antigravity 2 text field","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-voice-input-field.webp",[429,12266,12267,12268,12271],{},"Antigravity 2 also introduces the concept of a ",[440,12269,12270],{},"Project",", which can span multiple local folders and operate with its own specific agent settings and permissions.",[429,12273,12274,12278],{},[432,12275],{"alt":12276,"src":12277},"Project selection and configuration menu in Antigravity 2 settings","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-project-menu.webp",[432,12279],{"alt":12280,"src":12281},"Creating a new AI project with folder path in Antigravity 2","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-project-creation.webp",[12231,12283],{},[473,12285,12287],{"id":12286},"_2-set-up-mcps-and-plugins","2. Set Up MCPs and Plugins",[429,12289,12290,12291,12294],{},"All Model Context Protocol (MCP) servers, plugins, and skills are managed under the ",[440,12292,12293],{},"Customizations"," section in the Settings menu:",[429,12296,12297],{},[432,12298],{"alt":12299,"src":12300},"Customizations tab in settings for managing MCP servers and skills","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-settings-customizations.webp",[429,12302,12303],{},"Currently, the only available plugins are from Google, but hopefully, more will be released in the future.",[429,12305,12306],{},[432,12307],{"alt":12308,"src":12309},"List of official Google plugins and integrations in Antigravity 2","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-google-plugins-list.webp",[2125,12311,12313],{"id":12312},"adding-an-available-mcp-server","Adding an Available MCP Server",[429,12315,12316],{},"To install a pre-configured MCP Server (e.g., GitHub):",[532,12318,12319,12324],{},[487,12320,4217,12321,460],{},[440,12322,12323],{},"Add MCP+",[487,12325,7505,12326,460],{},[440,12327,12328],{},"GitHub MCP Server",[429,12330,12331,12335,12339],{},[432,12332],{"alt":12333,"src":12334},"Adding a pre-configured MCP server by clicking Add MCP plus button","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-add-mcp-button.webp",[432,12336],{"alt":12337,"src":12338},"Selecting GitHub MCP Server from the list of available integrations","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-select-github-mcp.webp",[432,12340],{"alt":12341,"src":12342},"GitHub MCP server authorization and installation setup wizard","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-github-mcp-setup.webp",[429,12344,12345,12346],{},"The GitHub MCP Server setup ended with an error:\n",[432,12347],{"alt":12348,"src":12349},"Configuration error during GitHub MCP Server installation process","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-github-mcp-error.webp",[429,12351,12352,12353,12355,12356,12358,12359,12361],{},"Since we already have ",[494,12354,2751],{}," installed on macOS, we can bypass this by executing the ",[494,12357,2751],{}," command directly within the conversation. However, we first need to explicitly add the ",[494,12360,2751],{}," command to our Antigravity permissions.",[429,12363,12364,12368],{},[432,12365],{"alt":12366,"src":12367},"Request dialog to add git command to sandboxed terminal permissions","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-add-git-permission-1.webp",[432,12369],{"alt":12370,"src":12371},"Granting git command execution permission in settings menu","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-add-git-permission-2.webp",[429,12373,12374,12375,12377,12378,12382],{},"Let's test out the prompt to see if the ",[494,12376,2751],{}," command now works:\n",[432,12379],{"alt":12380,"src":12381},"Submitting git status request within AI agent prompt box","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-git-command-test-1.webp",[432,12383],{"alt":12384,"src":12385},"Successful terminal execution of git status command inside the chat","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-git-command-test-2.webp",[12231,12387],{},[473,12389,12391],{"id":12390},"_3-add-custom-mcp-servers","3. Add Custom MCP Servers",[429,12393,12394],{},"If the MCP Server you want isn't on the default list, you can add it by editing the MCP configuration file directly. The configuration is located at:",[919,12396,12398],{"className":1027,"code":12397,"language":1029,"meta":424,"style":424},"~\u002F.gemini\u002Fconfig\u002Fmcp_config.json\n",[494,12399,12400],{"__ignoreMap":424},[927,12401,12402,12405],{"class":929,"line":930},[927,12403,12404],{"class":941},"~",[927,12406,12407],{"class":937},"\u002F.gemini\u002Fconfig\u002Fmcp_config.json\n",[429,12409,12410],{},"Let's add some Cloudflare MCP Servers as an example. Because Cloudflare supports dynamic client registration, we only need to enable OAuth. Add the following to your JSON configuration:",[919,12412,12414],{"className":2865,"code":12413,"language":2867,"meta":424,"style":424},"    \"cloudflare-api\": {\n      \"serverUrl\": \"https:\u002F\u002Fmcp.cloudflare.com\u002Fmcp\",\n      \"oauth\": {\n        \"enabled\": true\n      }\n    },\n    \"cloudflare-docs\": {\n      \"serverUrl\": \"https:\u002F\u002Fdocs.mcp.cloudflare.com\u002Fmcp\"\n    },\n    \"cloudflare-bindings\": {\n      \"serverUrl\": \"https:\u002F\u002Fbindings.mcp.cloudflare.com\u002Fmcp\",\n      \"oauth\": {\n        \"enabled\": true\n      }\n    },\n    \"cloudflare-builds\": {\n      \"serverUrl\": \"https:\u002F\u002Fbuilds.mcp.cloudflare.com\u002Fmcp\",\n      \"oauth\": {\n        \"enabled\": true\n      }\n    },\n    \"cloudflare-observability\": {\n      \"serverUrl\": \"https:\u002F\u002Fobservability.mcp.cloudflare.com\u002Fmcp\",\n      \"oauth\": {\n        \"enabled\": true\n      }\n    }\n",[494,12415,12416,12429,12449,12461,12473,12477,12484,12497,12514,12520,12533,12552,12564,12576,12580,12586,12599,12618,12630,12642,12646,12652,12665,12684,12696,12708,12712],{"__ignoreMap":424},[927,12417,12418,12420,12423,12425,12427],{"class":929,"line":930},[927,12419,7567],{"class":941},[927,12421,12422],{"class":1040},"cloudflare-api",[927,12424,3650],{"class":941},[927,12426,578],{"class":937},[927,12428,2874],{"class":941},[927,12430,12431,12433,12436,12438,12440,12442,12445,12447],{"class":929,"line":1056},[927,12432,7580],{"class":941},[927,12434,12435],{"class":933},"serverUrl",[927,12437,3650],{"class":941},[927,12439,1253],{"class":941},[927,12441,3240],{"class":941},[927,12443,12444],{"class":1040},"https:\u002F\u002Fmcp.cloudflare.com\u002Fmcp",[927,12446,3650],{"class":941},[927,12448,7597],{"class":941},[927,12450,12451,12453,12455,12457,12459],{"class":929,"line":1063},[927,12452,7580],{"class":941},[927,12454,7826],{"class":933},[927,12456,3650],{"class":941},[927,12458,1253],{"class":941},[927,12460,2904],{"class":941},[927,12462,12463,12465,12467,12469,12471],{"class":929,"line":1070},[927,12464,7616],{"class":941},[927,12466,7839],{"class":1036},[927,12468,3650],{"class":941},[927,12470,1253],{"class":941},[927,12472,1353],{"class":941},[927,12474,12475],{"class":929,"line":1891},[927,12476,7850],{"class":941},[927,12478,12479,12482],{"class":929,"line":1896},[927,12480,12481],{"class":941},"    }",[927,12483,7597],{"class":937},[927,12485,12486,12488,12491,12493,12495],{"class":929,"line":1902},[927,12487,7567],{"class":941},[927,12489,12490],{"class":1040},"cloudflare-docs",[927,12492,3650],{"class":941},[927,12494,578],{"class":937},[927,12496,2874],{"class":941},[927,12498,12499,12501,12503,12505,12507,12509,12512],{"class":929,"line":2238},[927,12500,7580],{"class":941},[927,12502,12435],{"class":933},[927,12504,3650],{"class":941},[927,12506,1253],{"class":941},[927,12508,3240],{"class":941},[927,12510,12511],{"class":1040},"https:\u002F\u002Fdocs.mcp.cloudflare.com\u002Fmcp",[927,12513,1923],{"class":941},[927,12515,12516,12518],{"class":929,"line":1667},[927,12517,12481],{"class":941},[927,12519,7597],{"class":937},[927,12521,12522,12524,12527,12529,12531],{"class":929,"line":2344},[927,12523,7567],{"class":941},[927,12525,12526],{"class":1040},"cloudflare-bindings",[927,12528,3650],{"class":941},[927,12530,578],{"class":937},[927,12532,2874],{"class":941},[927,12534,12535,12537,12539,12541,12543,12545,12548,12550],{"class":929,"line":2350},[927,12536,7580],{"class":941},[927,12538,12435],{"class":933},[927,12540,3650],{"class":941},[927,12542,1253],{"class":941},[927,12544,3240],{"class":941},[927,12546,12547],{"class":1040},"https:\u002F\u002Fbindings.mcp.cloudflare.com\u002Fmcp",[927,12549,3650],{"class":941},[927,12551,7597],{"class":941},[927,12553,12554,12556,12558,12560,12562],{"class":929,"line":2356},[927,12555,7580],{"class":941},[927,12557,7826],{"class":933},[927,12559,3650],{"class":941},[927,12561,1253],{"class":941},[927,12563,2904],{"class":941},[927,12565,12566,12568,12570,12572,12574],{"class":929,"line":2361},[927,12567,7616],{"class":941},[927,12569,7839],{"class":1036},[927,12571,3650],{"class":941},[927,12573,1253],{"class":941},[927,12575,1353],{"class":941},[927,12577,12578],{"class":929,"line":2367},[927,12579,7850],{"class":941},[927,12581,12582,12584],{"class":929,"line":3309},[927,12583,12481],{"class":941},[927,12585,7597],{"class":937},[927,12587,12588,12590,12593,12595,12597],{"class":929,"line":3320},[927,12589,7567],{"class":941},[927,12591,12592],{"class":1040},"cloudflare-builds",[927,12594,3650],{"class":941},[927,12596,578],{"class":937},[927,12598,2874],{"class":941},[927,12600,12601,12603,12605,12607,12609,12611,12614,12616],{"class":929,"line":3325},[927,12602,7580],{"class":941},[927,12604,12435],{"class":933},[927,12606,3650],{"class":941},[927,12608,1253],{"class":941},[927,12610,3240],{"class":941},[927,12612,12613],{"class":1040},"https:\u002F\u002Fbuilds.mcp.cloudflare.com\u002Fmcp",[927,12615,3650],{"class":941},[927,12617,7597],{"class":941},[927,12619,12620,12622,12624,12626,12628],{"class":929,"line":3333},[927,12621,7580],{"class":941},[927,12623,7826],{"class":933},[927,12625,3650],{"class":941},[927,12627,1253],{"class":941},[927,12629,2904],{"class":941},[927,12631,12632,12634,12636,12638,12640],{"class":929,"line":3863},[927,12633,7616],{"class":941},[927,12635,7839],{"class":1036},[927,12637,3650],{"class":941},[927,12639,1253],{"class":941},[927,12641,1353],{"class":941},[927,12643,12644],{"class":929,"line":3869},[927,12645,7850],{"class":941},[927,12647,12648,12650],{"class":929,"line":3878},[927,12649,12481],{"class":941},[927,12651,7597],{"class":937},[927,12653,12654,12656,12659,12661,12663],{"class":929,"line":4529},[927,12655,7567],{"class":941},[927,12657,12658],{"class":1040},"cloudflare-observability",[927,12660,3650],{"class":941},[927,12662,578],{"class":937},[927,12664,2874],{"class":941},[927,12666,12667,12669,12671,12673,12675,12677,12680,12682],{"class":929,"line":4982},[927,12668,7580],{"class":941},[927,12670,12435],{"class":933},[927,12672,3650],{"class":941},[927,12674,1253],{"class":941},[927,12676,3240],{"class":941},[927,12678,12679],{"class":1040},"https:\u002F\u002Fobservability.mcp.cloudflare.com\u002Fmcp",[927,12681,3650],{"class":941},[927,12683,7597],{"class":941},[927,12685,12686,12688,12690,12692,12694],{"class":929,"line":4991},[927,12687,7580],{"class":941},[927,12689,7826],{"class":933},[927,12691,3650],{"class":941},[927,12693,1253],{"class":941},[927,12695,2904],{"class":941},[927,12697,12698,12700,12702,12704,12706],{"class":929,"line":4999},[927,12699,7616],{"class":941},[927,12701,7839],{"class":1036},[927,12703,3650],{"class":941},[927,12705,1253],{"class":941},[927,12707,1353],{"class":941},[927,12709,12710],{"class":929,"line":5007},[927,12711,7850],{"class":941},[927,12713,12714],{"class":929,"line":5012},[927,12715,7700],{"class":941},[429,12717,12718,12719,12721,12722,12725],{},"Go back to the ",[440,12720,12293],{}," section in the app and click the ",[440,12723,12724],{},"Refresh"," button. You will now see the Cloudflare MCP Servers listed, pending authorisation.",[429,12727,12728],{},[432,12729],{"alt":12730,"src":12731},"Cloudflare MCP servers listed in customization menu pending authorization","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-cloudflare-mcp-pending.webp",[429,12733,4231,12734,12737,12738,12741],{},[440,12735,12736],{},"Authenticate"," next to the MCP Server. This will open an authentication page in your web browser. Once authenticated, an ",[440,12739,12740],{},"auth code"," will be generated.",[429,12743,12744],{},[432,12745],{"alt":12746,"src":12747},"Web browser displaying dynamic OAuth authorization code for Cloudflare MCP","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-cloudflare-auth-code.webp",[429,12749,12750,12751,460],{},"Copy this auth code, paste it back into the text input field in Antigravity, and click ",[440,12752,12753],{},"Submit",[429,12755,12756],{},[432,12757],{"alt":12758,"src":12759},"Submitting OAuth verification code in Antigravity setup interface","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-cloudflare-auth-submit.webp",[12231,12761],{},[473,12763,12765],{"id":12764},"_4-add-custom-skills","4. Add Custom Skills",[429,12767,12768,12769,12772,12773,3953],{},"Currently, adding custom skills ",[440,12770,12771],{},"cannot"," be done directly through the desktop application's UI. Instead, they must be added directly to the ",[494,12774,12775],{},"~\u002F.gemini\u002Fconfig\u002Fskills",[429,12777,12778,12779,12782,12783],{},"Because we use the ",[494,12780,12781],{},"npx skills"," CLI to centralise all our agent skills, any newly added skill can be made available to all agents, including Antigravity. ",[894,12784,12785,12786,10262],{},"(For a deeper dive on this, refer to our article: ",[443,12787,358],{"href":359},[429,12789,12790,12791,12793],{},"Initially, when typing ",[494,12792,8356],{}," in the conversation box, the skills list appears empty:",[429,12795,12796],{},[432,12797],{"alt":12798,"src":12799},"Command box displaying empty skills list when typing slash shortcut","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-empty-skills-list.webp",[429,12801,12802,12803,12805],{},"It appears Antigravity 2 doesn't automatically read from the global skills folder (",[494,12804,8602],{},"). To fix this, we need to create a symbolic link pointing to the Antigravity config directory:",[919,12807,12809],{"className":1027,"code":12808,"language":1029,"meta":424,"style":424},"ln -s ~\u002F.agents\u002Fskills\u002Fexcalidraw-diagram ~\u002F.gemini\u002Fconfig\u002Fskills\u002Fexcalidraw-diagram\n",[494,12810,12811],{"__ignoreMap":424},[927,12812,12813,12815,12817,12820],{"class":929,"line":930},[927,12814,3636],{"class":1036},[927,12816,3492],{"class":1040},[927,12818,12819],{"class":1040}," ~\u002F.agents\u002Fskills\u002Fexcalidraw-diagram",[927,12821,12822],{"class":1040}," ~\u002F.gemini\u002Fconfig\u002Fskills\u002Fexcalidraw-diagram\n",[429,12824,12825],{},"Once linked, the skill becomes available in the application!",[429,12827,12828],{},[432,12829],{"alt":12830,"src":12831},"Excalidraw diagram skill successfully showing in Antigravity command list","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-excalidraw-skill-available.webp",[12231,12833],{},[473,12835,12837],{"id":12836},"_5-test-a-simple-task","5. Test a Simple Task",[429,12839,12840],{},"Now that everything is configured, let's run a test.",[429,12842,12843],{},[432,12844],{"alt":12845,"src":12846},"Submitting a test task to list D1 databases via Cloudflare server","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-test-simple-task-prompt.webp",[429,12848,12849],{},"As shown below, the model successfully detects and utilises the newly added Cloudflare MCP Server to handle the request.",[429,12851,12852],{},[432,12853],{"alt":12854,"src":12855},"AI agent successfully executing D1 database listing using Cloudflare MCP","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002Fantigravity-test-task-success.webp",[12231,12857],{},[473,12859,7999],{"id":7998},[429,12861,12862],{},"Antigravity 2 represents a major shift from a traditional IDE to an accessible desktop application, empowering everyday users to act as orchestrators for any task.",[429,12864,12865],{},"However, Antigravity 2 needs some polish. When functionalities fail, debugging can be frustrating due to vague error handling. Additionally, the official documentation feels unrefined—likely AI-generated—as several references and file paths are currently incorrect.",[1611,12867,12868],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":424,"searchDepth":1056,"depth":1063,"links":12870},[12871,12872,12873,12876,12877,12878,12879],{"id":1723,"depth":1063,"text":1724},{"id":12235,"depth":1056,"text":12236},{"id":12286,"depth":1056,"text":12287,"children":12874},[12875],{"id":12312,"depth":1070,"text":12313},{"id":12390,"depth":1056,"text":12391},{"id":12764,"depth":1056,"text":12765},{"id":12836,"depth":1056,"text":12837},{"id":7998,"depth":1056,"text":7999},[1631],"2026-06-05","Discover what's new in Google Antigravity 2. Read our hands-on guide to installing the app, testing AI agent tasks, and manually adding custom MCP servers","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSetup%20Antigravity%202.0\u002FEN-Setup-Antigravity-2.0.webp","Google Antigravity 2 Review & Setup: AI Agents, MCPs & Plugins",{"schemaOrg":12886,"robots":1665,"sitemap":12888},[12887],{"@type":1642,"headline":12884,"description":12882},{"lastmod":12881},{"title":12884,"description":12882,"ogTitle":390,"ogDescription":12882,"twitterTitle":390,"twitterDescription":12882},[],"VbtqEQ6bitoC6HaBCzoZttJycUoyob0N_X-jD18Vtvg",{"id":12893,"title":358,"author":1673,"body":12894,"category":13308,"date":13309,"description":13310,"extension":1636,"image":13311,"imageAlt":13312,"isPublished":1059,"meta":13313,"minRead":1070,"navigation":1059,"path":41,"seo":13319,"stem":360,"tags":13320,"updatedAt":1673,"__hash__":13321},"article\u002Fen\u002Farticle\u002Fcentralised-the-skills-for-agents.md",{"type":426,"value":12895,"toc":13298},[12896,12906,12909,12932,12945,12949,12959,12975,12985,12992,12995,13017,13023,13034,13051,13060,13070,13074,13081,13102,13105,13111,13121,13128,13131,13151,13161,13165,13171,13243,13249,13253,13289,13295],[429,12897,12898,12899,12902,12903,12905],{},"If you run multiple AI agents or CLIs on your computer—whether it's Hermes, Claude Code, Codex, Antigravity, Kimi, or other supported tools—you've probably hit a frustrating issue: ",[440,12900,12901],{},"skills fragmentation",". Every agent or CLI maintains its own separate ",[494,12904,12000],{}," folder, which leads to duplicate installations, version drift, and management overhead.",[429,12907,12908],{},"In our work with AI agents, we frequently ran into the following issues:",[484,12910,12911,12917,12923],{},[487,12912,12913,12916],{},[440,12914,12915],{},"Multiple installs",": Installing a new skill for one agent, then install it again and again for others.",[487,12918,12919,12922],{},[440,12920,12921],{},"Version drift",": Customising or fixing a skill for one agent, forgetting to update the rest, and ending up with agents behaving differently.",[487,12924,12925,12928,12929,12931],{},[440,12926,12927],{},"Skills management",": Having to go through every ",[494,12930,12000],{}," folder for each agent across our system to see what skills were actually installed.",[429,12933,597,12934,12936,12937,12939,12940,460],{},[494,12935,12781],{}," CLI, an open-source CLI from Vercel,  solves the issue by letting you manage one centralised ",[494,12938,12000],{}," folder and share it across all your agents. You can check out the ",[443,12941,12943,8641],{"href":8563,"rel":12942},[447],[494,12944,12781],{},[473,12946,12948],{"id":12947},"centralised-folder","Centralised Folder",[429,12950,12951,12952,12954,12955,12958],{},"The concept is simple: if we point every agent's ",[494,12953,12000],{}," folder to the ",[440,12956,12957],{},"same physical folder",", the fragmentation problem completely disappears.",[429,12960,12961,12962,12964,12965,12967,12968,12971,12972,12974],{},"When you install a skill using ",[494,12963,12781],{}," CLI, the skill is downloaded to the centralised folder on your machine (",[494,12966,8602],{},"). The CLI then creates a ",[440,12969,12970],{},"symlink"," (which is just a pointer) from each agent's ",[494,12973,12000],{}," folder back to that centralised folder.",[429,12976,12977,12978,12981,12982,12984],{},"For example, when Claude Code looks for skills in ",[494,12979,12980],{},"~\u002F.claude\u002Fskills\u002F",", it gets transparently redirected to ",[494,12983,8602],{},". If you make a tweak to a skill in that centralised folder, every single agent sees the update instantly. No manual copying, no sync scripts, and no wasted disk storage.",[473,12986,12988,12989,12991],{"id":12987},"installing-npx-skills-and-adding-a-skill","Installing ",[494,12990,12781],{}," and Adding a Skill",[429,12993,12994],{},"Run the following command to get it started, and add our first skill:",[919,12996,12998],{"className":1027,"code":12997,"language":1029,"meta":424,"style":424},"npx skills add https:\u002F\u002Fgithub.com\u002Fcoleam00\u002Fexcalidraw-diagram-skill --skill excalidraw-diagram\n",[494,12999,13000],{"__ignoreMap":424},[927,13001,13002,13004,13006,13008,13011,13014],{"class":929,"line":930},[927,13003,7592],{"class":1036},[927,13005,8577],{"class":1040},[927,13007,1050],{"class":1040},[927,13009,13010],{"class":1040}," https:\u002F\u002Fgithub.com\u002Fcoleam00\u002Fexcalidraw-diagram-skill",[927,13012,13013],{"class":1040}," --skill",[927,13015,13016],{"class":1040}," excalidraw-diagram\n",[429,13018,13019],{},[432,13020],{"alt":13021,"src":13022},"Using npx skills add command to install a skill from GitHub","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FCentralised%20the%20skills%20for%20agents\u002Fnpx-skills-add-command.webp",[429,13024,13025,13026,13029,13030],{},"The CLI will ask whether to set this up for a specific project or globally. We usually recommend choosing ",[440,13027,13028],{},"global"," so all supported agents can access it:\n",[432,13031],{"alt":13032,"src":13033},"Selecting global installation option in npx skills CLI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FCentralised%20the%20skills%20for%20agents\u002Fnpx-skills-install-global-prompt.webp",[429,13035,13036,13037,13039,13040,1342,13043,13047],{},"Next, make sure to select ",[494,13038,8598],{}," to ensure a ",[440,13041,13042],{},"single source of truth",[432,13044],{"alt":13045,"src":13046},"Choosing symlink method for skill synchronization","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FCentralised%20the%20skills%20for%20agents\u002Fnpx-skills-symlink-option.webp",[432,13048],{"alt":13049,"src":13050},"Successful installation and symlink creation confirmation in CLI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FCentralised%20the%20skills%20for%20agents\u002Fnpx-skills-installation-completed.webp",[429,13052,13053,13054,1342,13056],{},"Once done, we can verify that the skill is installed in the centralised folder at ",[494,13055,8602],{},[432,13057],{"alt":13058,"src":13059},"Verifying installed skills in the centralized directory","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FCentralised%20the%20skills%20for%20agents\u002Fnpx-skills-directory-verification.webp",[429,13061,13062,13063,13065,13066],{},"Open up the Kimi CLI (or any other agent), and the ",[494,13064,10185],{}," skill is available and ready to use!\n",[432,13067],{"alt":13068,"src":13069},"Kimi CLI showing loaded and ready centralized skills","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FCentralised%20the%20skills%20for%20agents\u002Fkimi-cli-skills-integration.webp",[473,13071,13073],{"id":13072},"creating-a-skill-from-scratch","Creating a Skill from Scratch",[429,13075,13076,13077,13080],{},"To build your own skills, you can use Anthropic's ",[494,13078,13079],{},"skill-creator"," tool. Install it like this:",[919,13082,13084],{"className":1027,"code":13083,"language":1029,"meta":424,"style":424},"npx skills add https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fskills --skill skill-creator\n",[494,13085,13086],{"__ignoreMap":424},[927,13087,13088,13090,13092,13094,13097,13099],{"class":929,"line":930},[927,13089,7592],{"class":1036},[927,13091,8577],{"class":1040},[927,13093,1050],{"class":1040},[927,13095,13096],{"class":1040}," https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fskills",[927,13098,13013],{"class":1040},[927,13100,13101],{"class":1040}," skill-creator\n",[429,13103,13104],{},"Now, in Kimi or any other agent, enter the following prompt:",[919,13106,13109],{"className":13107,"code":13108,"language":4598},[4596],"Use the skill-creator to help me build a skill for creating a product landing page\n",[494,13110,13108],{"__ignoreMap":424},[429,13112,13113,13114,13116,13117],{},"Kimi or your agent will automatically pick up the ",[494,13115,13079],{}," and walk you through the process step-by-step:\n",[432,13118],{"alt":13119,"src":13120},"Interactive skill-creator wizard executing in Kimi CLI","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FCentralised%20the%20skills%20for%20agents\u002Fkimi-cli-skill-creator-setup.webp",[473,13122,13124,13125,13127],{"id":13123},"other-handy-npx-skills-commands","Other Handy ",[494,13126,12781],{}," Commands",[429,13129,13130],{},"Here are some other handy commands:",[484,13132,13133,13139,13145],{},[487,13134,13135,13138],{},[494,13136,13137],{},"npx skills ls -g",": List all globally installed skills",[487,13140,13141,13144],{},[494,13142,13143],{},"npx skills update",": Keep all skills up to date with one command",[487,13146,13147,13150],{},[494,13148,13149],{},"npx skills remove",": Interactively uninstall\u002Fremove a skill",[429,13152,13153,13154,13160],{},"Please refer to the ",[443,13155,13157,13159],{"href":8563,"rel":13156},[447],[494,13158,12781],{}," GitHub repo"," for more commands and reference.",[473,13162,13164],{"id":13163},"taking-it-a-step-further","Taking It a Step Further",[429,13166,13167,13168,13170],{},"Since all skills are now in one place (",[494,13169,8602],{},"), we can initialise it as a Git repository and push it to GitHub or GitLab.",[919,13172,13174],{"className":1027,"code":13173,"language":1029,"meta":424,"style":424},"cd ~\u002F.agents\u002Fskills\ngit init\ngit add .\ngit commit -m \"Initial skills folder\"\ngit remote add origin https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fskills\ngit push -u origin main\n",[494,13175,13176,13183,13190,13198,13214,13229],{"__ignoreMap":424},[927,13177,13178,13180],{"class":929,"line":930},[927,13179,2775],{"class":958},[927,13181,13182],{"class":1040}," ~\u002F.agents\u002Fskills\n",[927,13184,13185,13187],{"class":929,"line":1056},[927,13186,2751],{"class":1036},[927,13188,13189],{"class":1040}," init\n",[927,13191,13192,13194,13196],{"class":929,"line":1063},[927,13193,2751],{"class":1036},[927,13195,1050],{"class":1040},[927,13197,4855],{"class":1040},[927,13199,13200,13202,13204,13207,13209,13212],{"class":929,"line":1070},[927,13201,2751],{"class":1036},[927,13203,12138],{"class":1040},[927,13205,13206],{"class":1040}," -m",[927,13208,3240],{"class":941},[927,13210,13211],{"class":1040},"Initial skills folder",[927,13213,1923],{"class":941},[927,13215,13216,13218,13221,13223,13226],{"class":929,"line":1891},[927,13217,2751],{"class":1036},[927,13219,13220],{"class":1040}," remote",[927,13222,1050],{"class":1040},[927,13224,13225],{"class":1040}," origin",[927,13227,13228],{"class":1040}," https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fskills\n",[927,13230,13231,13233,13235,13238,13240],{"class":929,"line":1896},[927,13232,2751],{"class":1036},[927,13234,12109],{"class":1040},[927,13236,13237],{"class":1040}," -u",[927,13239,13225],{"class":1040},[927,13241,13242],{"class":1040}," main\n",[429,13244,13245,13246,460],{},"Now, we have a complete history of all skill changes, meaning we can easily roll back if an update breaks something. Plus, we can seamlessly sync the skills across multiple machines (like a laptop and desktop) by running a quick ",[494,13247,13248],{},"git pull",[473,13250,13252],{"id":13251},"a-few-things-to-keep-in-mind-security-risks","A Few Things to Keep in Mind (Security & Risks)",[484,13254,13255,13261,13267,13277,13283],{},[487,13256,13257,13260],{},[440,13258,13259],{},"Compatibility varies",": Not all agent platforms support every feature (like custom hooks or specific allowed tools) yet. A skill might work great in one agent but fall short in another.",[487,13262,13263,13266],{},[440,13264,13265],{},"Trust the source",": Only install skills from trusted sources.",[487,13268,13269,13272,13273,13276],{},[440,13270,13271],{},"Review before running",": If you are using a custom or third-party skill, review the files (especially in the ",[494,13274,13275],{},"scripts\u002F"," folder) before letting your agent run it.",[487,13278,13279,13282],{},[440,13280,13281],{},"Least privilege",": Try not to give a skill more tool permissions or access than it absolutely needs to do its job.",[487,13284,13285,13288],{},[440,13286,13287],{},"Never hardcode secrets",": Keep your API keys and secrets out of your skill files.",[429,13290,13291,13292,13294],{},"Setting up a centralised \"single source of truth\" with ",[494,13293,12781],{}," has saved our team from frustration and duplicate work. It is highly recommended to give it a try—the AI capabilities scale as skills grow!",[1611,13296,13297],{},"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 .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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}",{"title":424,"searchDepth":1056,"depth":1063,"links":13299},[13300,13301,13303,13304,13306,13307],{"id":12947,"depth":1056,"text":12948},{"id":12987,"depth":1056,"text":13302},"Installing npx skills and Adding a Skill",{"id":13072,"depth":1056,"text":13073},{"id":13123,"depth":1056,"text":13305},"Other Handy npx skills Commands",{"id":13163,"depth":1056,"text":13164},{"id":13251,"depth":1056,"text":13252},[1631],"2026-06-04","Running multiple AI agents like Claude Code or Kimi? Learn how to fix skills fragmentation and manage a single, centralized skills folder using npx skills CLI.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FCentralised%20the%20skills%20for%20agents\u002FSolving-AI-Agent-Skills-Fragmentation-with-npx-skills.webp","How to solve AI agent skills fragmentation using npx skills",{"schemaOrg":13314,"robots":1665,"sitemap":13317},[13315],{"@type":1642,"headline":13316,"description":13310},"How to Solve AI Agent Skills Fragmentation Using npx skills",{"lastmod":13318},"2026-06-03",{"title":13316,"description":13310,"ogTitle":358,"ogDescription":13310,"twitterTitle":358,"twitterDescription":13310},[],"iM-S5fnNzR3S0oqgwcACXz8vzr_zoPHhzClj5X_a-0A",{"id":13323,"title":370,"author":1673,"body":13324,"category":13556,"date":13557,"description":13558,"extension":1636,"image":13559,"imageAlt":13560,"isPublished":1059,"meta":13561,"minRead":2238,"navigation":1059,"path":47,"seo":13565,"stem":372,"tags":13566,"updatedAt":1673,"__hash__":13567},"article\u002Fen\u002Farticle\u002Fhow-to-secure-nodewarden-at-cloudflare.md",{"type":426,"value":13325,"toc":13547},[13326,13329,13332,13346,13350,13357,13359,13363,13366,13370,13400,13404,13407,13472,13476,13479,13541,13544],[429,13327,13328],{},"The moment your NodeWarden is exposed to the public on the Internet, it starts attracting thousands of automated bots scrapping for vulnerabilities 24\u002F7. To protect your sensitive data, You need to put NodeWarden instance in the maximum lockdown possible.",[429,13330,13331],{},"To secure your NodeWarden instance, you can use one of two Cloudflare features:",[484,13333,13334,13340],{},[487,13335,13336,13339],{},[440,13337,13338],{},"Cloudflare IP Access Rules:"," Allows you to block, challenge, or permit traffic based on specific IP addresses or countries.",[487,13341,13342,13345],{},[440,13343,13344],{},"Cloudflare Zero Trust (Recommend):"," Acts as a secure gateway that makes your NodeWarden instance completely invisible to the public, only letting authorised users through.",[2125,13347,13349],{"id":13348},"why-we-recommend-cloudflare-zero-trust","Why we recommend Cloudflare Zero Trust",[429,13351,13352,13353,13356],{},"We strongly advise using Cloudflare Zero Trust since IP Access Rules are tied to IP addresses or countries, meaning you need to manually update the your rules every time you travel or if you have a dynamic IP address. Cloudflare Zero Trust on the other hand relies on your ",[440,13354,13355],{},"identity",", not your location—giving you seamless, secure access to NodeWarden.",[12231,13358],{},[473,13360,13362],{"id":13361},"configuration-guide","Configuration Guide",[429,13364,13365],{},"Follow these steps to configure Cloudflare Zero Trust for NodeWarden.",[874,13367,13369],{"id":13368},"phase-1-getting-started","Phase 1: Getting Started",[532,13371,13372,13379,13386,13393],{},[487,13373,13374,13375],{},"In your Cloudflare dashboard, click on 'Zero Trust' from left menu\n",[432,13376],{"alt":13377,"src":13378},"Cloudflare dashboard sidebar showing the Zero Trust option selected in the navigation menu.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-dashboard-zero-trust-sidebar.webp",[487,13380,13381,13382],{},"Click on 'Access controls' then click on 'Applications'\n",[432,13383],{"alt":13384,"src":13385},"Cloudflare Zero Trust navigation menu with Access controls section expanded.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-zero-trust-access-controls-menu.webp",[487,13387,13388,13389],{},"You may be asked to 'Choose a plan'.\n",[432,13390],{"alt":13391,"src":13392},"Cloudflare Zero Trust account setup screen prompting the user to choose a subscription plan.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-zero-trust-choose-plan-setup.webp",[487,13394,13395,13396],{},"Click on the 'Choose a plan' button and choose the 'Zero Trust Free'.\n",[432,13397],{"alt":13398,"src":13399},"The Zero Trust Free plan details page on Cloudflare, highlighting the Select plan button.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-zero-trust-free-plan-selection.webp",[874,13401,13403],{"id":13402},"phase-2-secure-your-web-interface","Phase 2: Secure Your Web Interface",[429,13405,13406],{},"First, we will create an application to protect the NodeWarden web dashboard.",[532,13408,13409,13416,13423,13430,13436,13442,13449,13452,13459,13462],{},[487,13410,13411,13412],{},"Click on 'Create new application' to create the first application\n",[432,13413],{"alt":13414,"src":13415},"Cloudflare Access Applications dashboard featuring the Create new application button.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-create-new-application.webp",[487,13417,13418,13419],{},"Choose the 'Self-hosted and private'\n",[432,13420],{"alt":13421,"src":13422},"The Add an application modal in Cloudflare Access with Self-hosted and private application type selected.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-add-self-hosted-application.webp",[487,13424,13425,13426],{},"Enter the domain name of the NodeWarden.\n",[432,13427],{"alt":13428,"src":13429},"Cloudflare Access application configuration screen showing the public hostname set to warden.techvoyage.dev.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-application-public-hostname.webp",[487,13431,13432,13433],{},"Click on 'Create new policy' to create a policy.\n",[432,13434],{"alt":1781,"src":13435},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-no-policies-create-button.webp",[487,13437,13438,13439],{},"Select 'Emails' and enter an email under 'Policy rules'.\n",[432,13440],{"alt":1788,"src":13441},"https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-policy-rule-email.webp",[487,13443,13444,13445],{},"Enter a name and select 'Allow' under 'Policy details'.\n",[432,13446],{"alt":13447,"src":13448},"Cloudflare Access policy details screen showing the policy name NodeWarden-Web and the action set to Allow.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-policy-details-allow.webp",[487,13450,13451],{},"Click 'Save Policy' to create the policy.",[487,13453,13454,13455],{},"Enter a name and select '1 month' under the 'Details' section.\n",[432,13456],{"alt":13457,"src":13458},"Final configuration summary for a Cloudflare Access application named NodeWarden-Web with a one-month session duration.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-application-final-details.webp",[487,13460,13461],{},"Click on 'Create' to create the application.",[487,13463,13464,13467,13468],{},[440,13465,13466],{},"Test it:"," Open the domain on the web browser, you will see the 'Cloudflare Access' asking for email.\n",[432,13469],{"alt":13470,"src":13471},"A preview of the Cloudflare Access login screen for NodeWarden-Web, prompting for an email address.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-login-screen-preview.webp",[874,13473,13475],{"id":13474},"phase-3-allow-bitwarden-clients-syncing-api-bypass","Phase 3: Allow BitWarden Clients Syncing (API Bypass)",[429,13477,13478],{},"The desktop and mobile BitWarden apps cannot process Cloudflare's email login screen, we need to create a second application that allows traffic to bypass the login screen specifically for API syncing.",[532,13480,13481,13492,13507,13511,13518,13525,13527,13534],{},[487,13482,13483,13484,13487,13488,13491],{},"Go back to Applications and click ",[440,13485,13486],{},"Create new application",", choosing ",[440,13489,13490],{},"Self-hosted and private"," again.",[487,13493,13494,13495,13498,13499,13502,13503],{},"Enter the 'api\u002F",[894,13496,13497],{},"', 'identity\u002F","', 'notifications\u002F",[894,13500,13501],{},"', and 'icons\u002F","' in the Destinations.\n",[432,13504],{"alt":13505,"src":13506},"Configuring multiple public hostnames for API bypass in Cloudflare Access, including api, identity, notifications, and icons paths.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-api-bypass-destinations.webp",[487,13508,13432,13509],{},[432,13510],{"alt":1781,"src":13435},[487,13512,13513,13514],{},"Select 'Everyone' under 'Policy rules'.\n",[432,13515],{"alt":13516,"src":13517},"Cloudflare Access policy rule configuration with Everyone selected to allow broad access for specific paths.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-policy-rule-everyone.webp",[487,13519,13520,13521],{},"Enter a name and select 'Bypass' under 'Policy details'.\n",[432,13522],{"alt":13523,"src":13524},"Cloudflare Access policy details for NodeWarden-API with the action set to Bypass.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-policy-details-bypass.webp",[487,13526,13451],{},[487,13528,13529,13530],{},"Enter a name and select '1 month' for 'Session Duration'.\n",[432,13531],{"alt":13532,"src":13533},"Final configuration screen for the NodeWarden-API application in Cloudflare Access.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-api-application-final-details.webp",[487,13535,13536,13537],{},"You should have 2 applications created.\n",[432,13538],{"alt":13539,"src":13540},"The Cloudflare Access applications dashboard showing both the Web and API applications successfully created.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-access-applications-list-final.webp",[473,13542,13543],{"id":6116},"Final thought",[429,13545,13546],{},"Just remember that Cloudflare is your outer shield. To maintain a truly secure vault, ensure you are still using a strong master password, utilising Two-Factor Authentication (2FA) , and keeping your Cloudflare account secure.",{"title":424,"searchDepth":1056,"depth":1063,"links":13548},[13549,13550,13555],{"id":13348,"depth":1070,"text":13349},{"id":13361,"depth":1056,"text":13362,"children":13551},[13552,13553,13554],{"id":13368,"depth":1063,"text":13369},{"id":13402,"depth":1063,"text":13403},{"id":13474,"depth":1063,"text":13475},{"id":6116,"depth":1056,"text":13543},[2569,9428],"2026-05-27","The moment your NodeWarden is exposed to the public on the Internet, it starts attracting thousands of automated bots scrapping for vulnerabilities 24\u002F7.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FHow%20to%20secure%20NodeWarden%20at%20Cloudflare\u002Fsecure-nodewarden-cloudflare-integration-guide.webp","Step-by-step guide thumbnail for securing a NodeWarden vault with Cloudflare integration, featuring a digital safe with a padlock and a server rack protected by Cloudflare security.",{"schemaOrg":13562,"robots":1665,"sitemap":13564},[13563],{"@type":1642,"headline":370,"description":13558},{"lastmod":13557},{"title":370,"description":13558,"ogTitle":370,"ogDescription":13558,"twitterTitle":370,"twitterDescription":13558},[],"skmetmxWa0gDtpaRa9Xx9U_NHD-GMsL2p17SMSYYpWY",{"id":13569,"title":386,"author":1673,"body":13570,"category":14102,"date":14103,"description":14104,"extension":1636,"image":14105,"imageAlt":14106,"isPublished":1059,"meta":14107,"minRead":2238,"navigation":1059,"path":55,"seo":14112,"stem":388,"tags":14113,"updatedAt":1673,"__hash__":14114},"article\u002Fen\u002Farticle\u002Fself-hosting-nodewarden-at-cloudflare.md",{"type":426,"value":13571,"toc":14089},[13572,13575,13581,13585,13768,13772,13791,13795,13821,13825,13878,13882,13921,13925,13955,13959,13962,13966,13991,13995,14014,14018,14021,14038,14043,14046,14049,14061,14065,14078,14080],[429,13573,13574],{},"Your passwords are your most critical digital property, and keeping them secure means keeping them in your own hands. By self-hosting your password manager; you take control of your own security.",[429,13576,13577,13580],{},[440,13578,13579],{},"BitWarden"," is widely regarded as one of most trusted in password management domain and its source code is made available under AGPL-3.0 licence. An unofficial BitWarden compatible server, NodeWarden, is written in Typescript and can be deployed for free on Cloudflare.",[2125,13582,13584],{"id":13583},"feature-comparison-with-the-official-bitwarden-server","Feature Comparison with the Official BitWarden Server",[603,13586,13587,13602],{},[606,13588,13589],{},[609,13590,13591,13594,13596,13599],{},[612,13592,13593],{},"Capability",[612,13595,13579],{},[612,13597,13598],{},"NodeWarden",[612,13600,13601],{},"Notes",[632,13603,13604,13619,13634,13646,13658,13673,13689,13704,13720,13732,13744,13757],{},[609,13605,13606,13609,13612,13614],{},[637,13607,13608],{},"Web Vault",[637,13610,13611],{},"✅",[637,13613,13611],{},[637,13615,13616],{},[440,13617,13618],{},"Original Web Vault interface",[609,13620,13621,13627,13629,13631],{},[637,13622,13623,13624],{},"Full sync ",[494,13625,13626],{},"\u002Fapi\u002Fsync",[637,13628,13611],{},[637,13630,13611],{},[637,13632,13633],{},"Compatibility optimised for official clients",[609,13635,13636,13639,13641,13643],{},[637,13637,13638],{},"Attachment upload \u002F download",[637,13640,13611],{},[637,13642,13611],{},[637,13644,13645],{},"Cloudflare R2 or KV",[609,13647,13648,13651,13653,13655],{},[637,13649,13650],{},"Send",[637,13652,13611],{},[637,13654,13611],{},[637,13656,13657],{},"Supports both text and file Sends",[609,13659,13660,13663,13665,13667],{},[637,13661,13662],{},"Import \u002F Export",[637,13664,13611],{},[637,13666,13611],{},[637,13668,13669,13670],{},"Supports BitWarden JSON \u002F CSV \u002F ",[440,13671,13672],{},"ZIP import with attachments",[609,13674,13675,13680,13682,13684],{},[637,13676,13677],{},[440,13678,13679],{},"Cloud Backup Center",[637,13681,8539],{},[637,13683,13611],{},[637,13685,13686],{},[440,13687,13688],{},"Scheduled backup to WebDAV \u002F S3",[609,13690,13691,13694,13697,13699],{},[637,13692,13693],{},"Password hint (web)",[637,13695,13696],{},"⚠️ Limited",[637,13698,13611],{},[637,13700,13701],{},[440,13702,13703],{},"No email required",[609,13705,13706,13709,13711,13713],{},[637,13707,13708],{},"TOTP \u002F Steam TOTP",[637,13710,13611],{},[637,13712,13611],{},[637,13714,13715,13716,13719],{},"Includes ",[494,13717,13718],{},"steam:\u002F\u002F"," support",[609,13721,13722,13725,13727,13729],{},[637,13723,13724],{},"Multi-user",[637,13726,13611],{},[637,13728,13611],{},[637,13730,13731],{},"Invite-based registration",[609,13733,13734,13737,13739,13741],{},[637,13735,13736],{},"Organizations \u002F Collections \u002F Member roles",[637,13738,13611],{},[637,13740,8539],{},[637,13742,13743],{},"Not implemented",[609,13745,13746,13749,13751,13754],{},[637,13747,13748],{},"Login 2FA",[637,13750,13611],{},[637,13752,13753],{},"⚠️ Partial",[637,13755,13756],{},"Currently only user-level TOTP",[609,13758,13759,13762,13764,13766],{},[637,13760,13761],{},"SSO \u002F SCIM \u002F Enterprise directory",[637,13763,13611],{},[637,13765,8539],{},[637,13767,13743],{},[874,13769,13771],{"id":13770},"what-we-need","What we need:",[532,13773,13774,13779,13785],{},[487,13775,13776],{},[440,13777,13778],{},"A GitHub Account",[487,13780,13781,13784],{},[440,13782,13783],{},"A Cloudflare Account"," (Free) with R2 Storage enabled.",[487,13786,13787,13790],{},[894,13788,13789],{},"Optional:"," A custom domain name managed in Cloudflare.",[874,13792,13794],{"id":13793},"phase-1-prepare-the-code","Phase 1: Prepare the Code:",[532,13796,13797,13814],{},[487,13798,13799,13800,13804,13805,13809,13810],{},"Fork the NodeWarden repository from ",[443,13801,13802],{"href":13802,"rel":13803},"https:\u002F\u002Fgithub.com\u002FTech-Voyage-Dev\u002Fnodewarden",[447]," or original repository, ",[443,13806,13807],{"href":13807,"rel":13808},"https:\u002F\u002Fgithub.com\u002Fshuaiplus\u002Fnodewarden",[447]," in GitHub\n",[432,13811],{"alt":13812,"src":13813},"Forking the NodeWarden repository on GitHub","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Ffork-nodewarden-repo.webp",[487,13815,13816,13817],{},"Enable the Sync Upstream Workflow\n",[432,13818],{"alt":13819,"src":13820},"Enabling the Sync Upstream workflow in GitHub Actions","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fenable-sync-upstream.webp",[874,13822,13824],{"id":13823},"phase-2-deploy-to-cloudflare","Phase 2: Deploy to Cloudflare",[532,13826,13827,13834,13845],{},[487,13828,13829,13830],{},"Create a Worker Application in Cloudflare\n",[432,13831],{"alt":13832,"src":13833},"Creating a new Worker application in the Cloudflare dashboard","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fcreate-cloudflare-worker.webp",[487,13835,13836,13837,13841],{},"Select 'Continue with GitHub' to deploy the app.\n",[432,13838],{"alt":13839,"src":13840},"Deploying the NodeWarden app by connecting to GitHub","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fdeploy-github-repo.webp",[432,13842],{"alt":13843,"src":13844},"Cloudflare Worker build and deployment progress","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-deploy-status.webp",[487,13846,13847,13848,13851,13852,13855,13856,13859,13860],{},"Wait a few moments for Cloudflare to build and deploy your app. It will give you a default ",[494,13849,13850],{},"worker.dev"," URL.\n",[440,13853,13854],{},"(Optional) Add a Custom Domain:"," * In your Cloudflare Worker settings, go to the ",[440,13857,13858],{},"Settings"," tab.\n",[484,13861,13862,13867],{},[487,13863,4231,13864,460],{},[440,13865,13866],{},"+ Add",[487,13868,13869,13870,13874],{},"Type in your preferred domain and follow the prompts.\n",[432,13871],{"alt":13872,"src":13873},"Navigating to custom domain settings in Cloudflare Worker","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fworker-settings-custom-domain.webp",[432,13875],{"alt":13876,"src":13877},"Adding a custom domain to the Cloudflare Worker","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fadd-custom-domain.webp",[874,13879,13881],{"id":13880},"phase-3-secure-your-server-the-jwt-secret","Phase 3: Secure Your Server (The JWT Secret)",[532,13883,13884,13887,13897,13915],{},[487,13885,13886],{},"Head to the web browser and enter the custom domain name or the generated 'worker.dev' domain.",[487,13888,13889,13890,10666,13893],{},"You will get '",[440,13891,13892],{},"JWT_SECRET is missing'",[432,13894],{"alt":13895,"src":13896},"JWT_SECRET is missing error message on NodeWarden server","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fjwt-secret-missing-error.webp",[487,13898,13899,13900,13902,13903,13906,13907,13911],{},"Copy the generated secret key and head back to the Settings tab on the NodeWarden Worker, then click on '",[440,13901,13866],{},"' button on '",[440,13904,13905],{},"Variables and Secrets","' section.\n",[432,13908],{"alt":13909,"src":13910},"Variables and Secrets section in Cloudflare Worker settings","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fworker-variables-secrets.webp",[432,13912],{"alt":13913,"src":13914},"Adding the generated JWT secret to Cloudflare Worker variables","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fadd-jwt-secret.webp",[487,13916,13917,13918,1836],{},"Enter the generated secret and click on the '",[440,13919,13920],{},"Deploy \u002F Save",[874,13922,13924],{"id":13923},"phase-4-create-your-admin-account","Phase 4: Create Your Admin Account",[532,13926,13927,13934,13945,13952],{},[487,13928,13929,13930],{},"Go back to the web browser and refresh the page, you will get the following login page.\n",[432,13931],{"alt":13932,"src":13933},"NodeWarden server login page","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fnodewarden-login.webp",[487,13935,13936,13937,13940,13941],{},"Click on '",[440,13938,13939],{},"Create Account","' to create the admin account.\n",[432,13942],{"alt":13943,"src":13944},"Clicking the Create Account button on NodeWarden login page","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fcreate-account-button.webp",[487,13946,13947,13948],{},"Login using the created admin account to the Dashboard.\n",[432,13949],{"alt":13950,"src":13951},"NodeWarden admin dashboard overview","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fnodewarden-dashboard.webp",[487,13953,13954],{},"Now we have the server deployed and running. We start configuring the BitWarden clients.",[874,13956,13958],{"id":13957},"phase-5-connect-your-devices","Phase 5: Connect Your Devices",[429,13960,13961],{},"You can use the official BitWarden apps on all your devices.",[2125,13963,13965],{"id":13964},"chrome-extension","Chrome Extension",[532,13967,13968,13971,13974,13981,13988],{},[487,13969,13970],{},"Install the BitWarden Chrome extension",[487,13972,13973],{},"Open the extension.",[487,13975,13976,13977],{},"Click the link next to 'Accessing:' at the bottom of the popup.\n",[432,13978],{"alt":13979,"src":13980},"Selecting self-hosted option in Bitwarden Chrome extension","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fbitwarden-extension-self-hosted.webp",[487,13982,13983,13984],{},"Enter the domain name of the NodeWarden server.\n",[432,13985],{"alt":13986,"src":13987},"Entering server URL in Bitwarden Chrome extension","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fbitwarden-extension-domain.webp",[487,13989,13990],{},"Save the settings and log in with your account.",[2125,13992,13994],{"id":13993},"ios-app","iOS App",[532,13996,13997,14000,14007],{},[487,13998,13999],{},"Install the BitWarden app from the App Store",[487,14001,14002,14003],{},"Open the app and click on 'Self-hosted' next to 'Logging in on:'\n",[432,14004],{"alt":14005,"src":14006},"Accessing self-hosted settings in Bitwarden iOS app","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fbitwarden-ios-self-hosted.webp",[487,14008,14009,14010],{},"Enter the domain name of the NodeWarden server and click on '✓' button.\n",[432,14011],{"alt":14012,"src":14013},"Configuring server URL in Bitwarden iOS app","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fbitwarden-ios-domain.webp",[2125,14015,14017],{"id":14016},"other-clients","Other Clients",[429,14019,14020],{},"NodeWarden has been tested and confirmed compatible with these official BitWarden clients:",[484,14022,14023,14026,14029,14032,14035],{},[487,14024,14025],{},"✅ Windows desktop",[487,14027,14028],{},"✅ Android\u002FiOS mobile apps",[487,14030,14031],{},"✅ Browser extensions",[487,14033,14034],{},"✅ Linux desktop",[487,14036,14037],{},"⚠️ macOS desktop (not fully verified)",[14039,14040,14042],"h1",{"id":14041},"vault-backup","Vault Backup",[429,14044,14045],{},"NodeWarden allows you to back up your vault to a local computer or remote storage (WebDAV or S3-compatible storage).",[429,14047,14048],{},"To automate remote backups:",[484,14050,14051,14054],{},[487,14052,14053],{},"Configure the remote storage details inside the NodeWarden dashboard.",[487,14055,14056,14057],{},"Make sure the Cron task is set on Cloudflare Worker settings for auto remote backup.\n",[432,14058],{"alt":14059,"src":14060},"Configuring Cron triggers for automatic vault backups in Cloudflare","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fcloudflare-worker-cron.webp",[14039,14062,14064],{"id":14063},"final-security-thoughts","Final Security thoughts",[484,14066,14067,14070,14073],{},[487,14068,14069],{},"Secure the Cloudflare account access, otherwise the data can be compromised. Enable the Two-Factor Authentication (2FA) or Passkey on your Cloudflare account immediately.",[487,14071,14072],{},"Host the NodeWarden on a dedicated Cloudflare account. Do not share resources with other web apps to minimise the security risks.",[487,14074,14075],{},[443,14076,14077],{"href":371},"Secure NodeWarden with Cloudflare",[14039,14079,6124],{"id":6123},[484,14081,14082],{},[487,14083,14084],{},[443,14085,14088],{"href":14086,"rel":14087},"https:\u002F\u002Fnodewarden.app\u002Fguide\u002Fstart",[447],"Official NodeWarden Start Guide",{"title":424,"searchDepth":1056,"depth":1063,"links":14090},[14091,14092,14093,14094,14095,14096,14097],{"id":13583,"depth":1070,"text":13584},{"id":13770,"depth":1063,"text":13771},{"id":13793,"depth":1063,"text":13794},{"id":13823,"depth":1063,"text":13824},{"id":13880,"depth":1063,"text":13881},{"id":13923,"depth":1063,"text":13924},{"id":13957,"depth":1063,"text":13958,"children":14098},[14099,14100,14101],{"id":13964,"depth":1070,"text":13965},{"id":13993,"depth":1070,"text":13994},{"id":14016,"depth":1070,"text":14017},[2569,9428],"2026-05-25","Your passwords are your most critical digital property, and keeping them secure means keeping them in your own hands.","https:\u002F\u002Finimages.techvoyage.dev\u002Farticles\u002FSelf%20hosting%20NodeWarden%20at%20Cloudflare\u002Fself-hosting-bitwarden-vault.webp","Thumbnail for self-hosting Bitwarden compatible server tutorial, showing a digital vault and a secure server rack.",{"schemaOrg":14108,"robots":1665,"sitemap":14111},[14109],{"@type":1642,"headline":14110,"description":14104},"How to Lock Passwords in Your Own Vault by Self Hosting BitWarden Compatible Server",{"lastmod":14103},{"title":14110,"description":14104,"ogTitle":14110,"ogDescription":14104,"twitterTitle":14110,"twitterDescription":14104},[],"OlnbweB6youyilckmZZDqy3do1DqY_IXZlCI7uMXhuI",1792489977958]