[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"url-settings":80,"blog-\u002Fblog\u002Fbuilding-pieces-productivity-app-with-gemini-ai":589,"blog-author-\u002Fblog\u002Fbuilding-pieces-productivity-app-with-gemini-ai":1127},{"id":4,"extension":5,"footer":6,"header":66,"meta":77,"stem":78,"__hash__":79},"navigation\u002Fdata\u002Fshared\u002Fnavigation.yml","yml",{"brand":7,"columns":10,"legal":56},{"name":8,"tagline":9},"Pieces","The memory layer for modern work.",[11,26,41],{"title":12,"links":13},"Product",[14,17,21,24],{"label":15,"href":16},"Pieces Desktop","\u002Fdownloads",{"label":18,"href":19,"external":20},"Pieces MCP","url:docs.mcp.overview",true,{"label":22,"href":23,"external":20},"Pieces APIs","url:docs.api",{"label":25,"href":16},"Downloads",{"title":27,"links":28},"Resources",[29,32,35,38],{"label":30,"href":31,"external":20},"Documentation","url:docs.home",{"label":33,"href":34},"Blog","\u002Fblog",{"label":36,"href":37},"Changelog","\u002Fchangelog",{"label":39,"href":40,"external":20},"GitHub","url:github.org",{"title":42,"links":43},"Company",[44,47,50,53],{"label":45,"href":46},"About","\u002Fabout",{"label":48,"href":49},"Enterprise","\u002Fenterprise",{"label":51,"href":52,"external":20},"Discord","url:social.discord",{"label":54,"href":55,"external":20},"X \u002F Twitter","url:social.x",[57,60,63],{"label":58,"href":59,"external":20},"Privacy Policy","url:legal.privacyPolicy",{"label":61,"href":62,"external":20},"Refund Policy","url:legal.refundPolicy",{"label":64,"href":65,"external":20},"Terms of Service","url:legal.terms",{"links":67,"signIn":68,"contact":71,"cta":74},[],{"label":69,"href":70},"Sign in","url:portal.home",{"label":72,"href":73},"Contact sales","url:site.contact",{"label":75,"href":76},"Download","url:routes.downloads",{},"data\u002Fshared\u002Fnavigation","Ia8tCWWqcGvuaIro8jwZ3HH-MwI66yqJpWshASJdYQ0",{"id":81,"extension":5,"links":82,"meta":586,"stem":587,"__hash__":588},"urlSettings\u002Fdata\u002Fshared\u002Furls.yml",[83,87,91,95,99,103,107,111,115,119,123,127,131,135,139,143,147,151,155,159,163,167,171,175,179,183,187,191,195,199,203,207,211,215,219,223,227,231,235,238,242,246,249,253,257,261,265,269,273,277,281,285,289,293,297,301,305,309,313,317,321,325,329,333,337,341,345,349,353,357,361,365,369,373,377,381,385,389,393,396,400,404,408,412,416,420,423,426,429,432,436,440,444,448,452,456,460,464,468,472,476,480,484,488,492,495,499,503,507,511,515,519,523,527,531,534,538,542,546,550,553,557,561,565,568,571,575,579,582],{"key":84,"label":85,"href":86},"downloads.desktop","Desktop download page","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdownload",{"key":88,"label":89,"href":90},"downloads.macOS.dmgArm64","macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg-arm64\u002Fdownload",{"key":92,"label":93,"href":94},"downloads.macOS.dmgIntel","macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg\u002Fdownload",{"key":96,"label":97,"href":98},"downloads.macOS.pkg","macOS PKG","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg\u002Fdownload",{"key":100,"label":101,"href":102},"downloads.windows.appinstaller","Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fpieces_for_x.appinstaller",{"key":104,"label":105,"href":106},"downloads.windows.exe","Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-exe\u002Fdownload",{"key":108,"label":109,"href":110},"downloads.windows.suiteManager","Windows Suite Manager","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_suite_windows\u002Fappinstaller\u002Fdownload",{"key":112,"label":113,"href":114},"downloads.linux.flatpakRepo","Linux Flatpak repository","https:\u002F\u002Fbuilds.pieces.app\u002Fpieces-flatpak-repo\u002Fpieces-flatpak.flatpakrepo",{"key":116,"label":117,"href":118},"downloads.linux.snapDesktop","Linux Snap Desktop","https:\u002F\u002Fsnapcraft.io\u002Fpieces-for-developers",{"key":120,"label":121,"href":122},"downloads.linux.snapPiecesOS","Linux Snap PiecesOS","https:\u002F\u002Fsnapcraft.io\u002Fpieces-os",{"key":124,"label":125,"href":126},"downloads.piecesOS.macOS.dmgArm64","PiecesOS macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg-arm64\u002Fdownload",{"key":128,"label":129,"href":130},"downloads.piecesOS.macOS.dmgIntel","PiecesOS macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg\u002Fdownload",{"key":132,"label":133,"href":134},"downloads.piecesOS.windows.appinstaller","PiecesOS Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fos_server.appinstaller",{"key":136,"label":137,"href":138},"downloads.piecesOS.windows.exe","PiecesOS Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-exe\u002Fdownload",{"key":140,"label":141,"href":142},"downloads.guides.macOS","macOS installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fmacos-installation-guide",{"key":144,"label":145,"href":146},"downloads.guides.windows","Windows installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fwindows-installation-guide",{"key":148,"label":149,"href":150},"downloads.guides.linux","Linux installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide",{"key":152,"label":153,"href":154},"downloads.guides.piecesOS","PiecesOS manual installation","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fmanual-installation",{"key":156,"label":157,"href":158},"extensions.chrome","Chrome extension","https:\u002F\u002Fchrome.google.com\u002Fwebstore\u002Fdetail\u002Fpieces-save-code-snippets\u002Figbgibhbfonhmjlechmeefimncpekepm",{"key":160,"label":161,"href":162},"extensions.firefox","Firefox add-on","https:\u002F\u002Faddons.mozilla.org\u002Fen-US\u002Ffirefox\u002Faddon\u002Fpieces-save-code-from-the-web\u002F",{"key":164,"label":165,"href":166},"extensions.edge","Edge add-on","https:\u002F\u002Fmicrosoftedge.microsoft.com\u002Faddons\u002Fdetail\u002Fpieces-save-code-snippet\u002Fhglfimcdgonaeeobjckfdabcldfidmim",{"key":168,"label":169,"href":170},"extensions.vscode","VS Code extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.pieces-vscode",{"key":172,"label":173,"href":174},"extensions.visualStudio","Visual Studio extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.PiecesVisualStudio",{"key":176,"label":177,"href":178},"extensions.jetbrains","JetBrains plugin","https:\u002F\u002Fplugins.jetbrains.com\u002Fplugin\u002F17328-pieces--save-search-share--reuse-code-snippets",{"key":180,"label":181,"href":182},"extensions.obsidian","Obsidian plugin","https:\u002F\u002Fobsidian.md\u002Fplugins?id=pieces-for-developers",{"key":184,"label":185,"href":186},"extensions.sublime","Sublime package","https:\u002F\u002Fpackagecontrol.io\u002Fpackages\u002FPieces",{"key":188,"label":189,"href":190},"extensions.neovim","Neovim plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neo_vim",{"key":192,"label":193,"href":194},"extensions.jupyterlab","JupyterLab plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fjupyterlab-pieces",{"key":196,"label":197,"href":198},"extensions.cli","Pieces CLI","https:\u002F\u002Fpypi.org\u002Fproject\u002Fpieces-cli\u002F",{"key":200,"label":201,"href":202},"docs.home","Documentation home","https:\u002F\u002Fdocs.pieces.app",{"key":204,"label":205,"href":206},"docs.getStarted","Get started docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces",{"key":208,"label":209,"href":210},"docs.api","API docs","https:\u002F\u002Fdocs.pieces.app\u002Fapi",{"key":212,"label":213,"href":214},"docs.desktop.overview","Desktop overview","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop",{"key":216,"label":217,"href":218},"docs.desktop.onboarding","Desktop onboarding","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fonboarding",{"key":220,"label":221,"href":222},"docs.desktop.timeline","Desktop timeline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Ftimeline",{"key":224,"label":225,"href":226},"docs.desktop.summaries","Desktop summaries docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fsingle-click-summaries",{"key":228,"label":229,"href":230},"docs.desktop.search","Desktop conversational search docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconversational-search",{"key":232,"label":233,"href":234},"docs.desktop.drive","Desktop drive docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdrive",{"key":236,"label":237,"href":86},"docs.desktop.download","Desktop download docs",{"key":239,"label":240,"href":241},"docs.piecesOS.overview","PiecesOS overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies",{"key":243,"label":244,"href":245},"docs.piecesOS.details","PiecesOS details docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os",{"key":247,"label":248,"href":154},"docs.piecesOS.install","PiecesOS install docs",{"key":250,"label":251,"href":252},"docs.piecesOS.quickMenu","PiecesOS quick menu docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fquick-menu",{"key":254,"label":255,"href":256},"docs.piecesOS.storage","On-device storage docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fon-device-storage",{"key":258,"label":259,"href":260},"docs.piecesOS.troubleshooting","PiecesOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Ftroubleshooting",{"key":262,"label":263,"href":264},"docs.mcp.overview","MCP overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp",{"key":266,"label":267,"href":268},"docs.mcp.cursor","MCP Cursor docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcursor",{"key":270,"label":271,"href":272},"docs.mcp.vscode","MCP VS Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fvs-code",{"key":274,"label":275,"href":276},"docs.mcp.claudeDesktop","MCP Claude Desktop docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-desktop",{"key":278,"label":279,"href":280},"docs.mcp.claudeCode","MCP Claude Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-code",{"key":282,"label":283,"href":284},"docs.mcp.claudeCowork","MCP Claude Cowork docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-cowork",{"key":286,"label":287,"href":288},"docs.mcp.githubCopilot","MCP GitHub Copilot docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgithub-copilot",{"key":290,"label":291,"href":292},"docs.mcp.goose","MCP Goose docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoose",{"key":294,"label":295,"href":296},"docs.mcp.windsurf","MCP Windsurf docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fwindsurf",{"key":298,"label":299,"href":300},"docs.mcp.zed","MCP Zed docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fzed",{"key":302,"label":303,"href":304},"docs.mcp.jetbrains","MCP JetBrains docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fjetbrains-ides",{"key":306,"label":307,"href":308},"docs.mcp.continueDev","MCP Continue docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcontinue-dev",{"key":310,"label":311,"href":312},"docs.mcp.cline","MCP Cline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcline",{"key":314,"label":315,"href":316},"docs.mcp.raycast","MCP Raycast docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fraycast",{"key":318,"label":319,"href":320},"docs.mcp.rovoDevCli","MCP Rovo Dev CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Frovo-dev-cli",{"key":322,"label":323,"href":324},"docs.mcp.openaiCodexCli","MCP OpenAI Codex CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenai-codex-cli",{"key":326,"label":327,"href":328},"docs.mcp.googleGeminiCli","MCP Google Gemini CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoogle-gemini-cli",{"key":330,"label":331,"href":332},"docs.mcp.amazonQ","MCP Amazon Q docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Famazon-q-developer",{"key":334,"label":335,"href":336},"docs.mcp.chatgptDev","MCP ChatGPT Developer Mode docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fchatgpt-developer-mode",{"key":338,"label":339,"href":340},"docs.mcp.openclaw","MCP OpenClaw docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenclaw",{"key":342,"label":343,"href":344},"docs.mcp.mcpRemote","MCP Remote docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fmcp-remote",{"key":346,"label":347,"href":348},"docs.mcp.ngrok","MCP ngrok docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fngrok-setup",{"key":350,"label":351,"href":352},"docs.troubleshooting.macOS","macOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fmacos",{"key":354,"label":355,"href":356},"docs.troubleshooting.windows","Windows troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fwindows",{"key":358,"label":359,"href":360},"docs.troubleshooting.linux","Linux troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Flinux",{"key":362,"label":363,"href":364},"docs.privacy","Privacy and security docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fprivacy-security-your-data",{"key":366,"label":367,"href":368},"docs.support","Support docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fsupport",{"key":370,"label":371,"href":372},"portal.home","Pieces portal","https:\u002F\u002Fportal.pieces.app",{"key":374,"label":375,"href":376},"site.home","Website home","https:\u002F\u002Fpieces.app",{"key":378,"label":379,"href":380},"site.about","About page","https:\u002F\u002Fpieces.app\u002Fabout",{"key":382,"label":383,"href":384},"site.features","Features page","https:\u002F\u002Fpieces.app\u002Ffeatures",{"key":386,"label":387,"href":388},"site.plugins","Plugins page","https:\u002F\u002Fpieces.app\u002Fplugins",{"key":390,"label":391,"href":392},"site.contact","Contact page","https:\u002F\u002Fpieces.app\u002Fcontact",{"key":394,"label":36,"href":395},"site.changelog","https:\u002F\u002Fpieces.app\u002Fchangelog",{"key":397,"label":398,"href":399},"site.news","News","https:\u002F\u002Fpieces.app\u002Fnews",{"key":401,"label":402,"href":403},"site.events","Community events","https:\u002F\u002Fpieces.app\u002Fcommunity\u002Fevents",{"key":405,"label":406,"href":407},"site.userStories","User stories","https:\u002F\u002Fpieces.app\u002Fuser-stories",{"key":409,"label":410,"href":411},"site.academy","Academy","https:\u002F\u002Fpieces.app\u002Flearn\u002Facademy",{"key":413,"label":414,"href":415},"site.support","Website support","https:\u002F\u002Fpieces.app\u002Fsupport",{"key":417,"label":418,"href":419},"site.standup","Standup","https:\u002F\u002Fpieces.app\u002Fstandup",{"key":421,"label":33,"href":422},"site.blog","https:\u002F\u002Fcode.pieces.app\u002Fblog",{"key":424,"label":51,"href":425},"social.discord","https:\u002F\u002Fdiscord.gg\u002Fgetpieces",{"key":427,"label":54,"href":428},"social.x","https:\u002F\u002Fx.com\u002Fgetpieces",{"key":430,"label":431,"href":428},"social.twitter","Twitter",{"key":433,"label":434,"href":435},"social.instagram","Instagram","https:\u002F\u002Fwww.instagram.com\u002Fgetpieces\u002F",{"key":437,"label":438,"href":439},"social.tiktok","TikTok","https:\u002F\u002Fwww.tiktok.com\u002F@getpieces",{"key":441,"label":442,"href":443},"social.linkedin","LinkedIn","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fgetpieces\u002F",{"key":445,"label":446,"href":447},"social.youtube","YouTube","https:\u002F\u002Fyoutube.com\u002F@getpieces",{"key":449,"label":450,"href":451},"github.org","GitHub organization","https:\u002F\u002Fgithub.com\u002Fpieces-app",{"key":453,"label":454,"href":455},"github.support","GitHub support","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport",{"key":457,"label":458,"href":459},"github.issues","GitHub issues","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fissues",{"key":461,"label":462,"href":463},"github.discussions","GitHub discussions","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fdiscussions",{"key":465,"label":466,"href":467},"github.documentation","GitHub documentation","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fdocumentation",{"key":469,"label":470,"href":471},"github.opensource","GitHub open source","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fopensource",{"key":473,"label":474,"href":475},"github.sdks.python","Python SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-python",{"key":477,"label":478,"href":479},"github.sdks.typescript","TypeScript SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-typescript",{"key":481,"label":482,"href":483},"github.sdks.dart","Dart SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-dart",{"key":485,"label":486,"href":487},"github.sdks.kotlin","Kotlin SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-kotlin",{"key":489,"label":490,"href":491},"github.plugins.obsidian","Obsidian plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fobsidian-pieces",{"key":493,"label":494,"href":194},"github.plugins.jupyterlab","JupyterLab plugin repository",{"key":496,"label":497,"href":498},"github.plugins.sublime","Sublime plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_sublime",{"key":500,"label":501,"href":502},"github.plugins.neovim","Neovim plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neovim",{"key":504,"label":505,"href":506},"github.cliAgent","CLI agent repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fcli-agent",{"key":508,"label":509,"href":510},"github.mcpDart","MCP Dart repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fmcp_dart",{"key":512,"label":513,"href":514},"github.awesomePieces","Awesome Pieces repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fawesome-pieces",{"key":516,"label":517,"href":518},"legal.privacyPolicy","Privacy policy","https:\u002F\u002Fpieces.app\u002Flegal\u002Fprivacy-policy",{"key":520,"label":521,"href":522},"legal.refundPolicy","Refund policy","https:\u002F\u002Fpieces.app\u002Flegal\u002Frefund-policy",{"key":524,"label":525,"href":526},"legal.terms","Terms","https:\u002F\u002Fpieces.app\u002Flegal\u002Fterms",{"key":528,"label":529,"href":530},"legal.security","Legal security","https:\u002F\u002Fpieces.app\u002Flegal\u002Fsecurity",{"key":532,"label":533,"href":447},"videos.youtubeChannel","YouTube channel",{"key":535,"label":536,"href":537},"videos.gettingStartedDesktop","Getting started desktop video","https:\u002F\u002Fyoutu.be\u002FdUr1lRM_TYk",{"key":539,"label":540,"href":541},"videos.snippetDiscovery","Snippet discovery video","https:\u002F\u002Fyoutu.be\u002FG6vb1USw-30",{"key":543,"label":544,"href":545},"sales.bookACall","Book a sales call","https:\u002F\u002Fcalendar.app.google\u002FWVUDtUfNy5Vst3sH7",{"key":547,"label":548,"href":549},"sales.enterprise","Enterprise form","https:\u002F\u002Fgetpieces.typeform.com\u002Fto\u002FaVQFTvpE",{"key":551,"label":552,"href":463},"sales.feedback","Feedback discussions",{"key":554,"label":555,"href":556},"sales.earlyAccess","Early access form","https:\u002F\u002Fgetpieces.typeform.com\u002Fearlyaccess",{"key":558,"label":559,"href":560},"sales.supportEmail","Support email","mailto:support@pieces.app",{"key":562,"label":563,"href":564},"routes.home","Home route","\u002F",{"key":566,"label":567,"href":46},"routes.about","About route",{"key":569,"label":570,"href":16},"routes.downloads","Downloads route",{"key":572,"label":573,"href":574},"routes.pricing","Pricing route","\u002Fpricing",{"key":576,"label":577,"href":578},"routes.security","Security route","\u002Fsecurity",{"key":580,"label":581,"href":49},"routes.enterprise","Enterprise route",{"key":583,"label":584,"href":585},"routes.thankYou","Thank you \u002F download route","\u002Fthank-you",{},"data\u002Fshared\u002Furls","P27xKEauu8D-8sfyr0wR4giF0teFSaCuAQ8kgcICQdI",{"id":590,"title":591,"author":592,"authorPhoto":593,"authorPhotoAlt":594,"authorSlug":595,"body":596,"buttonText":1114,"buttonUrl":1115,"category":1116,"date":1117,"description":1118,"draft":1119,"editorsPick":1119,"extension":1120,"featured":20,"image":1121,"imageAlt":594,"meta":1122,"navigation":20,"ogImage":1121,"ogImageAlt":594,"path":1123,"seo":1124,"stem":1125,"tags":594,"__hash__":1126},"blog\u002Fblog\u002Fbuilding-pieces-productivity-app-with-gemini-ai.md","Building a daily productivity app with Pieces — Part 2: Adding AI Intelligence with Gemini","Bishoy Hany","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fbuilding-pieces-productivity-with-flutter-ui\u002Fauthor.jpeg",null,"bishoy-hany",{"type":597,"value":598,"toc":1093},"minimark",[599,611,624,636,639,662,667,675,685,688,694,701,705,708,722,726,737,743,752,756,762,768,782,789,793,805,810,816,822,826,832,837,841,847,852,856,859,865,868,901,912,916,919,925,928,934,940,944,951,957,961,967,973,976,996,1000,1003,1009,1012,1015,1032,1035,1039,1042,1048,1052,1058,1079,1085],[600,601,602,603,610],"p",{},"Welcome back! In ",[604,605,609],"a",{"href":606,"rel":607},"https:\u002F\u002Fpieces.app\u002Fblog\u002Fbuilding-daily-standup-generator-with-pieces-api-sdk",[608],"nofollow","Part 1,"," we built a complete PiecesOS service that:",[612,613,614,618,621],"ul",{},[615,616,617],"li",{},"Connects to PiecesOS and maintains a WebSocket connection",[615,619,620],{},"Fetches and caches workstream summaries grouped by day",[615,622,623],{},"Extracts the summary content from annotations",[600,625,626,627,631,632,635],{},"Now we have all of the infrastructure in place. But here's the thing: having raw summaries with their content is ",[628,629,630],"em",{},"cool",", but it's not exactly... useful. I mean, I have all this text about what I did, but what did I actually ",[628,633,634],{},"accomplish"," today?",[600,637,638],{},"That's where Part 2 comes in. We're going to use Google's Gemini AI to transform those raw summaries into actual insights. Think:",[612,640,641,647,652,657],{},[615,642,643],{},[644,645,646],"strong",{},"What did I work on?",[615,648,649],{},[644,650,651],{},"Which projects did I touch?",[615,653,654],{},[644,655,656],{},"Who did I collaborate with?",[615,658,659],{},[644,660,661],{},"What should I remember for tomorrow?",[663,664,666],"h2",{"id":665},"the-challenge","The challenge",[600,668,669,670,674],{},"Thanks to Part 1, we now have access to rich summary data using ",[671,672,673],"code",{},"SummaryWithContent",":",[676,677,682],"pre",{"className":678,"code":680,"language":681},[679],"language-text","\u002F\u002F lib\u002Fmodels\u002Fdaily_recap_models.dart\n\n\u002F\u002F Don't forget the imports!\nimport 'dart:convert';\nimport 'package:google_generative_ai\u002Fgoogle_generative_ai.dart';\nimport '..\u002Fmodels\u002Fdaily_recap_models.dart';\n\nSummaryWithContent {\n  id: \"4f302bfd-f3c2-4f85-aa79-e7cb314e111d\",\n  title: \"Implemented WebSocket sync\",\n  content: \"# Project XYZ\\nFixed critical authentication bug in OAuth token refresh.\n            Implemented real-time WebSocket synchronization with automatic \n            reconnection. Pair programmed with Bob on the WebSocket integration...\",\n  timestamp: 2025-11-04 14:32:15\n}\n","text",[671,683,680],{"__ignoreMap":684},"",[600,686,687],{},"This is great! But it's still just raw text. What we want are structured and actionable insights:",[676,689,692],{"className":690,"code":691,"language":681},[679],"SUMMARY:\n   Successfully fixed critical authentication bug and implemented \n   real-time WebSocket synchronization for better data flow.\n\nPROJECTS:\n   ✅ Authentication Service [completed]\n      Fixed OAuth token refresh logic\n\n   🔄 WebSocket Integration [in_progress]\n      Implemented real-time sync with automatic reconnection\n\nPEOPLE WORKED WITH:\n   • Alice (code review)\n   • Bob (pair programming)\n\nREMINDERS:\n   ⚠️  Test WebSocket with production load\n   ⚠️  Update documentation for new auth flow\nNOTES:\n  - Send a message in Google Chat about the progress!\n",[671,693,691],{"__ignoreMap":684},[600,695,696,697,700],{},"See the difference? One is data, the other is ",[644,698,699],{},"information",".",[663,702,704],{"id":703},"enter-gemini","Enter Gemini",[600,706,707],{},"Google's Gemini API is perfect for this. It can:",[612,709,710,713,716,719],{},[615,711,712],{},"Understand natural language",[615,714,715],{},"Extract structured information",[615,717,718],{},"Return JSON (which is exactly what we need!)",[615,720,721],{},"Process multiple summaries at once",[663,723,725],{"id":724},"setting-up","Setting up",[600,727,728,729,732,733,736],{},"First, add the Gemini SDK to ",[671,730,731],{},"pubspec.yaml"," below the ‘",[671,734,735],{},"git:","’ dependency:",[676,738,741],{"className":739,"code":740,"language":681},[679],"dependencies:\n  google_generative_ai: ^0.4.6\n",[671,742,740],{"__ignoreMap":684},[600,744,745,746,751],{},"You'll also need an API key. Get one from ",[604,747,750],{"href":748,"rel":749},"https:\u002F\u002Fmakersuite.google.com\u002Fapp\u002Fapikey",[608],"Google AI Studio"," – it's free for reasonable usage!",[663,753,755],{"id":754},"building-the-daily-recap-service","Building the daily recap service",[600,757,758,759,700],{},"Let's create a new service: ",[671,760,761],{},"lib\u002Fservices\u002Fdaily_recap_service.dart",[676,763,766],{"className":764,"code":765,"language":681},[679],"class DailyRecapService {\n  final GenerativeModel _model;\n\n  DailyRecapService({required String apiKey})\n      : _model = GenerativeModel(\n          model: 'gemini-2.5-flash-lite',  \u002F\u002F Fast, efficient, and cost-effective!\n          apiKey: apiKey,\n          generationConfig: GenerationConfig(\n            temperature: 0.7,  \u002F\u002F Balanced creativity\n            topK: 40,\n            topP: 0.95,\n            maxOutputTokens: 2048,\n            responseMimeType: 'application\u002Fjson',\n          ),\n        );\n\n  Future\u003CDailyRecapData> generateDailyRecap({\n    required DateTime date,\n    required List\u003CSummaryWithContent> summaries,\n  }) async {\n    \u002F\u002F We'll build this step by step!\n  }\n}\n",[671,767,765],{"__ignoreMap":684},[612,769,770,776],{},[615,771,772,775],{},[644,773,774],{},"gemini-2.5-flash-lite",": faster and more cost-effective",[615,777,778,781],{},[644,779,780],{},"temperature: 0.7",": Not too creative, not too rigid",[600,783,784,785,788],{},"Now, let's build the ",[671,786,787],{},"generateDailyRecap"," function piece by piece.",[663,790,792],{"id":791},"the-prompt-engineering","The prompt engineering",[600,794,795,800,801,804],{},[604,796,799],{"href":797,"rel":798},"https:\u002F\u002Fpieces.app\u002Fblog\u002Fllm-prompt-engineering",[608],"Crafting the right prompt"," is ",[644,802,803],{},"an art",". Here are some important tips:",[806,807,809],"h3",{"id":808},"avoid-vague-prompts","Avoid vague prompts",[676,811,814],{"className":812,"code":813,"language":681},[679],"Analyze these summaries and tell me what I did today.\n",[671,815,813],{"__ignoreMap":684},[600,817,818,821],{},[644,819,820],{},"Result:"," Always try to be specific. AI does not read your mind… yet! (Pieces does read your mind, but whatever 😉)",[806,823,825],{"id":824},"better-structure","Better structure",[676,827,830],{"className":828,"code":829,"language":681},[679],"Return JSON with: summary, projects, people.\n",[671,831,829],{"__ignoreMap":684},[600,833,834,836],{},[644,835,820],{}," Always say what do you expect the AI to return to be able to correctly parse it:",[806,838,840],{"id":839},"show-some-examples","Show some examples",[676,842,845],{"className":843,"code":844,"language":681},[679],"Extract and organize into this EXACT JSON format:\n{\n  \"summary\": \"Brief 1-2 sentence overview\",\n  \"people\": [\"Person1\", \"Person2\"],\n  \"projects\": [\n    {\n      \"name\": \"Project Name\",\n      \"description\": \"What was done\",\n      \"status\": \"in_progress\"  \u002F\u002F or \"completed\" or \"not_started\"\n    }\n  ],\n  \"reminders\": [\"Reminder 1\"],\n  \"notes\": [\"Important insight\"]\n}\n",[671,846,844],{"__ignoreMap":684},[600,848,849,851],{},[644,850,820],{}," AI is similar to humans; the best way to understand is by examples.",[806,853,855],{"id":854},"our-beautiful-prompt","Our beautiful prompt",[600,857,858],{},"Here's the final prompt we’ll use:",[676,860,863],{"className":861,"code":862,"language":681},[679],"\u002F\u002F lib\u002Fservices\u002Fdaily_recap_service.dart\n\n  \u002F\u002F Add below DailyRecapService() and above Future\u003C>\n\n  \u002F\u002F\u002F Build the prompt for Gemini\n  String _buildPrompt(DateTime date, String context) {\n    final dateStr =\n        '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';\n\n    return '''You are an AI assistant analyzing a developer's workstream summaries for the day: $dateStr.\n\nBased on the following workstream summaries, extract and organize the information into a structured daily recap.\n\nWORKSTREAM SUMMARIES:\n$context\n\nYour task is to analyze these summaries and create a comprehensive daily recap with the following information:\n\n1. **summary** (string, 1-2 sentences): A brief overview of what was accomplished today. Focus on the main achievements and work done.\n\n2. **people** (array of strings): List of people mentioned or collaborated with. Look for names, @mentions, or collaboration indicators. Can be empty if no one is mentioned.\n\n3. **projects** (array of objects): Projects worked on today. Each project should have:\n   - **name** (string): Project or feature name\n   - **description** (string): Brief description of what was done\n   - **status** (string): One of: \"completed\", \"in_progress\", or \"not_started\"\n\n4. **reminders** (array of strings): Action items, TODOs, or things to remember for later. Look for phrases like \"need to\", \"should\", \"TODO\", \"remember to\", etc. Can be empty.\n\n5. **notes** (array of strings): Important observations, learnings, or technical notes from the day. Look for insights, discoveries, or important information. Can be empty.\n\nIMPORTANT GUIDELINES:\n- Be concise but informative\n- Extract actual information from the summaries, don't make things up\n- If a category has no relevant information, use an empty array [] or empty string \"\"\n- For project status: use \"completed\" if the work is done, \"in_progress\" if actively working on it, \"not_started\" if mentioned but not begun\n- People names should be just the name (e.g., \"Alice\", \"Bob\")\n- Keep descriptions clear and specific\n\nReturn ONLY valid JSON in this exact format:\n{\n  \"summary\": \"Brief 1-2 sentence overview\",\n  \"people\": [\"Person1\", \"Person2\"],\n  \"projects\": [\n    {\n      \"name\": \"Project Name\",\n      \"description\": \"What was done\",\n      \"status\": \"in_progress\"\n    }\n  ],\n  \"reminders\": [\"Reminder 1\", \"Reminder 2\"],\n  \"notes\": [\"Note 1\", \"Note 2\"]\n}\n''';\n  }\n",[671,864,862],{"__ignoreMap":684},[600,866,867],{},"Why this works:",[869,870,871,877,883,889,895],"ol",{},[615,872,873,876],{},[644,874,875],{},"Clear role",": \"You are an AI assistant...\"",[615,878,879,882],{},[644,880,881],{},"Specific format",": Exact JSON structure",[615,884,885,888],{},[644,886,887],{},"Examples",": Shows what we want",[615,890,891,894],{},[644,892,893],{},"Constraints",": \"Don't make things up\", \"Empty arrays if no data\"",[615,896,897,900],{},[644,898,899],{},"Enum values",": Explicit status options",[600,902,903,904,907,908,911],{},"These two helper methods,",[671,905,906],{},"_buildPrompt"," and ",[671,909,910],{},"_buildSummariesContext"," (we'll see next), are what power our analysis. But where do they fit in the actual application?",[663,913,915],{"id":914},"sending-rich-context-to-gemini","Sending rich context to Gemini",[600,917,918],{},"Now that we have the actual summary content, we can build a rich prompt:",[676,920,923],{"className":921,"code":922,"language":681},[679]," \u002F\u002F lib\u002Fservices\u002Fdaily_recap_service.dart\n\n \u002F\u002F Add below _buildPrompt() and above generateDailyRecap()\n\n String _buildSummariesContext(List\u003CSummaryWithContent> summaries) {\n    final buffer = StringBuffer();\n\n    for (int i = 0; i \u003C summaries.length; i++) {\n      final summary = summaries[i];\n      buffer.writeln('Summary ${i + 1}:');\n      buffer.writeln('  ID: ${summary.id}');\n      buffer.writeln('  Title: ${summary.title}');\n      buffer.writeln(\n        '  Time: ${summary.timestamp.hour.toString().padLeft(2, '0')}:${summary.timestamp.minute.toString().padLeft(2, '0')}',\n      );\n      buffer.writeln('  Content: ${summary.content}');\n      buffer.writeln();\n    }\n\n    return buffer.toString();\n  }\n",[671,924,922],{"__ignoreMap":684},[600,926,927],{},"This formats each summary with structured labels and metadata, giving Gemini way more context to work with",[600,929,930,931],{},"Let’s add an empty factory method to create an empty ",[671,932,933],{},"DailyRecapData",[676,935,938],{"className":936,"code":937,"language":681},[679],"\u002F\u002F lib\u002Fservices\u002Fdaily_recap_service.dart\n\n\u002F\u002F Add below _buildPrompt() and above generateDailyRecap() \n factory DailyRecapData.empty(DateTime date) {\n    return DailyRecapData(\n      date: date,\n      summary: '',\n      people: [],\n      projects: [],\n      reminders: [],\n      notes: [],\n    );\n  }\n",[671,939,937],{"__ignoreMap":684},[663,941,943],{"id":942},"handling-the-response","Handling the Response",[600,945,946,947,950],{},"Gemini returns JSON (because we set ",[671,948,949],{},"responseMimeType","), so parsing is straightforward:",[676,952,955],{"className":953,"code":954,"language":681},[679],"\u002F\u002F lib\u002Fservices\u002Fdaily_recap_service.dart\n\n\u002F\u002F Replace the comment in generateDailyRecap() with this:\n\ntry {\n  final response = await _model.generateContent([Content.text(prompt)]);\n  print(\"Gemini response received. ${response.text}\");  \u002F\u002F Debug output\n  final rawText = response.text ?? '{}';\n      \n  \u002F\u002F Extract JSON from markdown code blocks\n  final jsonText = _extractJsonFromMarkdown(rawText);\n  final data = jsonDecode(jsonText) as Map\u003CString, dynamic>;\n\n  return DailyRecapData.fromJson(date, data); \u002F\u002F ... generate recap\n} catch (e) {\n  print('Error generating recap: $e');\n  return DailyRecapData.empty(date);  \u002F\u002F Safe fallback\n}\n",[671,956,954],{"__ignoreMap":684},[663,958,960],{"id":959},"putting-it-all-together-the-complete-generatedailyrecap-function","Putting it all together: the complete generateDailyRecap function",[600,962,963,964,966],{},"Now that we've seen all the pieces, here's how they fit together in the actual ",[671,965,787],{}," function (how yours should look 😉):",[676,968,971],{"className":969,"code":970,"language":681},[679],"Future\u003CDailyRecapData> generateDailyRecap({\n  required DateTime date,\n  required List\u003CSummaryWithContent> summaries,\n}) async {\n  \u002F\u002F Step 1: Handle edge case - no summaries\n  if (summaries.isEmpty) {\n    return DailyRecapData.empty(date);\n  }\n\n  \u002F\u002F Step 2: Build context from summaries using our helper method\n  final context = _buildSummariesContext(summaries);\n\n  \u002F\u002F Step 3: Craft the prompt using our prompt builder\n  final prompt = _buildPrompt(date, context);\n\n  try {\n    \u002F\u002F Step 4: Send to Gemini and get response\n    final response = await _model.generateContent([Content.text(prompt)]);\n    print(\"Gemini response received. ${response.text}\");\n    \n    \u002F\u002F Step 5: Parse the JSON response\n    final jsonText = response.text ?? '{}';\n    final data = jsonDecode(jsonText) as Map\u003CString, dynamic>;\n\n    \u002F\u002F Step 6: Convert to our data model and return\n    return DailyRecapData.fromJson(date, data);\n  } catch (e) {\n    print('Error generating daily recap: $e');\n    rethrow; \u002F\u002F Let the UI handle the error\n  }\n}\n",[671,972,970],{"__ignoreMap":684},[600,974,975],{},"See how it flows?",[869,977,978,981,984,987,990,993],{},[615,979,980],{},"Check for empty summaries",[615,982,983],{},"Build the context string from all summaries",[615,985,986],{},"Create the prompt with instructions",[615,988,989],{},"Send to Gemini",[615,991,992],{},"Parse the JSON response",[615,994,995],{},"Return structured data (or throw error)",[663,997,999],{"id":998},"the-data-models","The data models",[600,1001,1002],{},"I created clean data classes to work with:",[676,1004,1007],{"className":1005,"code":1006,"language":681},[679],"\u002F\u002F lib\u002Fmodels\u002Fdaily_recap_models.dart\n\n\u002F\u002F Add before SummaryWithContent class and after ProjectStatus {}\n\nclass ProjectData {\n  final String name;\n  final String description;\n  final ProjectStatus status;  \u002F\u002F enum: completed, inProgress, notStarted\n\n  ProjectData({\n    required this.name,\n    required this.description,\n    required this.status,\n  });\n\n  factory ProjectData.fromJson(Map\u003CString, dynamic> json) {\n    return ProjectData(\n      name: json['name'] as String,\n      description: json['description'] as String,\n      status: _statusFromString(json['status'] as String),\n    );\n  }\n\n  static ProjectStatus _statusFromString(String status) {\n    switch (status) {\n      case 'completed':\n        return ProjectStatus.completed;\n      case 'in_progress':\n        return ProjectStatus.inProgress;\n      case 'not_started':\n        return ProjectStatus.notStarted;\n      default:\n        return ProjectStatus.notStarted;\n    }\n  }\n}\n\nclass DailyRecapData {\n  final DateTime date;\n  final String summary;\n  final List\u003CString> people;\n  final List\u003CProjectData> projects;\n  final List\u003CString> reminders;\n  final List\u003CString> notes;\n\n  DailyRecapData({\n    required this.date,\n    required this.summary,\n    required this.people,\n    required this.projects,\n    required this.reminders,\n    required this.notes,\n  });\n\n  factory DailyRecapData.fromJson(DateTime date, Map\u003CString, dynamic> json) {\n    return DailyRecapData(\n      date: date,\n      summary: json['summary'] as String? ?? '',\n      people: (json['people'] as List\u003Cdynamic>?)\n              ?.map((e) => e as String)\n              .toList() ??\n          [],\n      projects: (json['projects'] as List\u003Cdynamic>?)\n              ?.map((e) => ProjectData.fromJson(e as Map\u003CString, dynamic>))\n              .toList() ??\n          [],\n      reminders: (json['reminders'] as List\u003Cdynamic>?)\n              ?.map((e) => e as String)\n              .toList() ??\n          [],\n      notes: (json['notes'] as List\u003Cdynamic>?)\n              ?.map((e) => e as String)\n              .toList() ??\n          [],\n    );\n  }\n}\n",[671,1008,1006],{"__ignoreMap":684},[600,1010,1011],{},"This gives us type safety and makes it easy to work with the data later.",[600,1013,1014],{},"Look at what Gemini did:",[612,1016,1017,1020,1023,1026,1029],{},[615,1018,1019],{},"✅ Understood that I was working on \"Pieces OS Integration\"",[615,1021,1022],{},"✅ Correctly identified it as \"completed\"",[615,1024,1025],{},"✅ Extracted actual reminders from my work",[615,1027,1028],{},"✅ Pulled out technical notes I discovered",[615,1030,1031],{},"✅ Wrote a coherent summary of the day",[600,1033,1034],{},"And it did all this from just timestamps and titles!",[806,1036,1038],{"id":1037},"real-world-example-what-gemini-generated","Real-world example: what Gemini generated",[600,1040,1041],{},"Here's an actual JSON response that Gemini generated from my workstream summaries:",[676,1043,1046],{"className":1044,"code":1045,"language":681},[679],"{\n  \"summary\": \"Today's work focused on enhancing user experience for video content, developing a tag generator, testing Flutter capabilities, and reviewing code and infrastructure. Significant progress was made on persona generation for AI training data.\",\n  \"people\": [],\n  \"projects\": [\n    {\n      \"name\": \"Video Analytics & User Experience\",\n      \"description\": \"Analyzed YouTube video analytics for 'Pieces' content and discussed strategies for improving new user experience by leveraging context and memory,\n considering phased UI exposure and temporary access keys.\",\n      \"status\": \"in_progress\"\n    },\n    {\n      \"name\": \"Tag Generator\",\n      \"description\": \"Generated a Python script for thematic tagging.\",\n      \"status\": \"completed\"\n    },\n    {\n      \"name\": \"Flutter macOS Dynamic Library Loading\",\n      \"description\": \"Demonstrated Flutter's macOS dynamic library loading and confirmed clipboard monitoring functionality and its integration with long-term memory.\",\n      \"status\": \"in_progress\"\n    },\n    {\n      \"name\": \"AI Persona Generation\",\n      \"description\": \"Discussed UI for AI persona generation and initiated content compilation for a partner. Presented the 'persona-query-tag-dataset-gen' project, det\nailing the creation of realistic user personas for the Pieces AI assistant, showcasing comprehensive attributes and providing an example of 'Anja Vestergaard'.\",\n      \"status\": \"in_progress\"\n    },\n    {\n      \"name\": \"ML Training & Django API\",\n      \"description\": \"Addressed an `UnboundLocalError` in ML training and validated nested task management for a Django API.\",\n      \"status\": \"completed\"\n    },\n    {\n      \"name\": \"Infrastructure Upgrades & Containerization\",\n      \"description\": \"Reviewed infrastructure upgrades, containerization strategies, cost optimizations, and bug fixes across multiple services, including timezone and \nuser invitation flows.\",\n      \"status\": \"in_progress\"\n    }\n  ],\n  \"reminders\": [],\n  \"notes\": [\n    \"Leveraging context and memory for new user experience improvements.\",\n    \"Clipboard monitoring functionality confirmed and integrated with long-term memory.\",\n    \"Objective for persona generation project is to generate authentic training data for the AI assistant.\"\n  ]\n}\n",[671,1047,1045],{"__ignoreMap":684},[663,1049,1051],{"id":1050},"complete-reference-implementation","Complete reference implementation",[600,1053,1054,1055,1057],{},"For your reference, here's the complete ",[671,1056,761],{}," file with everything we've built:",[612,1059,1060,1063,1069,1074],{},[615,1061,1062],{},"The service initialization with Gemini configuration",[615,1064,1065,1066,1068],{},"The ",[671,1067,787],{}," function that orchestrates everything",[615,1070,1065,1071,1073],{},[671,1072,910],{}," helper for formatting summaries",[615,1075,1065,1076,1078],{},[671,1077,906],{}," helper for crafting the AI prompt",[676,1080,1083],{"className":1081,"code":1082,"language":681},[679],"class DailyRecapService {\n  final GenerativeModel _model;\n  late final Box\u003CDailyRecapData> _cacheBox;\n\n  DailyRecapService({required String apiKey})\n    : _model = GenerativeModel(\n        model: 'gemini-2.5-flash-lite',\n        apiKey: apiKey,\n        generationConfig: GenerationConfig(\n          temperature: 0.7,\n          topK: 40,\n          topP: 0.95,\n          maxOutputTokens: 2048,\n          responseMimeType: 'application\u002Fjson',\n        ),\n      );\n\n  \u002F\u002F\u002F Generate a daily recap from workstream summaries with their content\n  \u002F\u002F\u002F Set forceRegenerate to true to bypass cache\n  Future\u003CDailyRecapData> generateDailyRecap({\n    required DateTime date,\n    required List\u003CSummaryWithContent> summaries,\n  }) async {\n    \u002F\u002F Check cache first (unless forcing regeneration)\n    if (summaries.isEmpty) {\n      return DailyRecapData.empty(date);\n    }\n\n    \u002F\u002F Build context from summaries\n    final context = _buildSummariesContext(summaries);\n\n    \u002F\u002F Craft the prompt\n    final prompt = _buildPrompt(date, context);\n\n    try {\n      final response = await _model.generateContent([Content.text(prompt)]);\n      \u002F\u002F ignore: avoid_print\n      print(\"Gemini response received. ${response.text}\");\n      final jsonText = response.text ?? '{}';\n\n      \u002F\u002F Parse the JSON response\n      final data = jsonDecode(jsonText) as Map\u003CString, dynamic>;\n\n      final recap = DailyRecapData.fromJson(date, data);\n\n      return recap;\n    } catch (e) {\n      \u002F\u002F ignore: avoid_print\n      print('Error generating daily recap: $e');\n      rethrow; \u002F\u002F Throw error so UI can handle it\n    }\n  }\n\n  \u002F\u002F\u002F Build context string from summaries with their content\n  String _buildSummariesContext(List\u003CSummaryWithContent> summaries) {\n    final buffer = StringBuffer();\n\n    for (int i = 0; i \u003C summaries.length; i++) {\n      final summary = summaries[i];\n      buffer.writeln('Summary ${i + 1}:');\n      buffer.writeln('  ID: ${summary.id}');\n      buffer.writeln('  Title: ${summary.title}');\n      buffer.writeln(\n        '  Time: ${summary.timestamp.hour.toString().padLeft(2, '0')}:${summary.timestamp.minute.toString().padLeft(2, '0')}',\n      );\n      buffer.writeln('  Content: ${summary.content}');\n      buffer.writeln();\n    }\n\n    return buffer.toString();\n  }\n\n\u002F\u002F\u002F Extract JSON from markdown code blocks\n  String _extractJsonFromMarkdown(String text) {\n    \u002F\u002F Remove markdown code block formatting\n    String cleaned = text.trim();\n    \n    \u002F\u002F Remove leading ```json or ```\n    if (cleaned.startsWith('```')) {\n      cleaned = cleaned.replaceFirst(RegExp(r'^```(?:json)?\\s*'), '');\n    }\n    \n    \u002F\u002F Remove trailing ```\n    if (cleaned.endsWith('```')) {\n      cleaned = cleaned.replaceFirst(RegExp(r'\\s*```$'), '');\n    }\n    \n    return cleaned.trim();\n  }\n\n  \u002F\u002F\u002F Build the prompt for Gemini\n  String _buildPrompt(DateTime date, String context) {\n    final dateStr =\n        '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';\n\n    return '''You are an AI assistant analyzing a developer's workstream summaries for the day: $dateStr.\n\nBased on the following workstream summaries, extract and organize the information into a structured daily recap.\n\nWORKSTREAM SUMMARIES:\n$context\n\nYour task is to analyze these summaries and create a comprehensive daily recap with the following information:\n\n1. **summary** (string, 1-2 sentences): A brief overview of what was accomplished today. Focus on the main achievements and work done.\n\n2. **people** (array of strings): List of people mentioned or collaborated with. Look for names, @mentions, or collaboration indicators. Can be empty if no one is mentioned.\n\n3. **projects** (array of objects): Projects worked on today. Each project should have:\n   - **name** (string): Project or feature name\n   - **description** (string): Brief description of what was done\n   - **status** (string): One of: \"completed\", \"in_progress\", or \"not_started\"\n\n4. **reminders** (array of strings): Action items, TODOs, or things to remember for later. Look for phrases like \"need to\", \"should\", \"TODO\", \"remember to\", etc. Can be empty.\n\n5. **notes** (array of strings): Important observations, learnings, or technical notes from the day. Look for insights, discoveries, or important information. Can be empty.\n\nIMPORTANT GUIDELINES:\n- Be concise but informative\n- Extract actual information from the summaries, don't make things up\n- If a category has no relevant information, use an empty array [] or empty string \"\"\n- For project status: use \"completed\" if the work is done, \"in_progress\" if actively working on it, \"not_started\" if mentioned but not begun\n- People names should be just the name (e.g., \"Alice\", \"Bob\")\n- Keep descriptions clear and specific\n\nReturn ONLY valid JSON in this exact format:\n{\n  \"summary\": \"Brief 1-2 sentence overview\",\n  \"people\": [\"Person1\", \"Person2\"],\n  \"projects\": [\n    {\n      \"name\": \"Project Name\",\n      \"description\": \"What was done\",\n      \"status\": \"in_progress\"\n    }\n  ],\n  \"reminders\": [\"Reminder 1\", \"Reminder 2\"],\n  \"notes\": [\"Note 1\", \"Note 2\"]\n}\n''';\n  }\n}\n",[671,1084,1082],{"__ignoreMap":684},[600,1086,1087,1092],{},[604,1088,1091],{"href":1089,"rel":1090},"https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fblog-dart-daily-stand-up-generator",[608],"Reference GitHub"," to view the full project.",{"title":684,"searchDepth":1094,"depth":1094,"links":1095},2,[1096,1097,1098,1099,1100,1107,1108,1109,1110,1113],{"id":665,"depth":1094,"text":666},{"id":703,"depth":1094,"text":704},{"id":724,"depth":1094,"text":725},{"id":754,"depth":1094,"text":755},{"id":791,"depth":1094,"text":792,"children":1101},[1102,1104,1105,1106],{"id":808,"depth":1103,"text":809},3,{"id":824,"depth":1103,"text":825},{"id":839,"depth":1103,"text":840},{"id":854,"depth":1103,"text":855},{"id":914,"depth":1094,"text":915},{"id":942,"depth":1094,"text":943},{"id":959,"depth":1094,"text":960},{"id":998,"depth":1094,"text":999,"children":1111},[1112],{"id":1037,"depth":1103,"text":1038},{"id":1050,"depth":1094,"text":1051},"Get started with Pieces","https:\u002F\u002Fpieces.app\u002F","AI & LLM","2025-12-04T00:00:00.000Z","Build a daily productivity app with Pieces (Part 2) by adding AI intelligence with Google Gemini, covering architecture, prompts, integrations, and practical tips to ship smarter workflows.",false,"md","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fbuilding-pieces-productivity-app-with-gemini-ai\u002Fhero.png",{},"\u002Fblog\u002Fbuilding-pieces-productivity-app-with-gemini-ai",{"title":591,"description":1118},"blog\u002Fbuilding-pieces-productivity-app-with-gemini-ai","6GCwtKeETL4aG6Ryj1d5vOdOkhFoC-use4iu2Yu0GGc",{"id":1128,"title":592,"body":1129,"description":1133,"draft":1119,"extension":1120,"meta":1136,"navigation":20,"path":1137,"photo":1138,"photoAlt":594,"seo":1139,"stem":1140,"__hash__":1141},"authors\u002Fauthors\u002Fbishoy-hany.md",{"type":597,"value":1130,"toc":1134},[1131],[600,1132,1133],{},"Bishoy Hany is a Software Engineer at Pieces, where he plays a key role in building developer-first AI experiences that run locally and respect user privacy. With a strong focus on performance, reliability, and intelligent automation, Bishoy works across the full stack to help shape the future of long-term memory and contextual AI.",{"title":684,"searchDepth":1094,"depth":1094,"links":1135},[],{},"\u002Fauthors\u002Fbishoy-hany","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fauthors\u002Fbishoy-hany.jpg",{"title":592,"description":1133},"authors\u002Fbishoy-hany","_m1q8mqNk1I4j1V0_YJSK0zuMS48DBT4Nqw9e3PZjMM"]