[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"url-settings":86,"blog-\u002Fblog\u002Fbuilding-pieces-productivity-app-with-gemini-ai":671,"blog-author-\u002Fblog\u002Fbuilding-pieces-productivity-app-with-gemini-ai":1210,"i-material-symbols:arrow-back-rounded":1225},{"id":4,"extension":5,"footer":6,"header":73,"meta":83,"stem":84,"__hash__":85},"navigation\u002Fdata\u002Fshared\u002Fnavigation.yml","yml",{"brand":7,"columns":13,"legal":63},{"name":8,"tagline":9,"downloadCta":10},"Pieces","The memory layer for modern work.",{"label":11,"href":12},"All downloads","\u002Fdownloads",[14,26,39,51],{"title":15,"links":16},"Product",[17,20,23],{"label":18,"href":19},"Pieces Desktop","\u002F",{"label":21,"href":22},"Pieces Enterprise","\u002Fenterprise",{"label":24,"href":25},"Pieces MCP","\u002Fmcp",{"title":27,"links":28},"Resources",[29,33,36],{"label":30,"href":31,"external":32},"Documentation","url:docs.home",true,{"label":34,"href":35},"Blog","\u002Fblog",{"label":37,"href":38,"external":32},"GitHub","url:github.org",{"title":40,"links":41},"Community",[42,45,48],{"label":43,"href":44,"external":32},"Discord","url:social.discord",{"label":46,"href":47,"external":32},"X \u002F Twitter","url:social.x",{"label":49,"href":50,"external":32},"LinkedIn","url:social.linkedin",{"title":52,"links":53},"Company",[54,57,60],{"label":55,"href":56},"About","\u002Fabout",{"label":58,"href":59},"Updates","\u002Fupdates",{"label":61,"href":62},"Contact","\u002Fcontact",[64,67,70],{"label":65,"href":66},"Privacy Policy","\u002Flegal\u002Fprivacy",{"label":68,"href":69},"Refund Policy","\u002Flegal\u002Frefund",{"label":71,"href":72},"Terms of Service","\u002Flegal\u002Fterms",{"links":74,"signIn":75,"contact":78,"cta":80},[],{"label":76,"href":77},"Manage account","url:portal.home",{"label":79,"href":62},"Get in touch",{"label":81,"href":82},"Download","url:routes.downloads",{},"data\u002Fshared\u002Fnavigation","XlSALC7vYCXHcmcXnjJViwIZKsqnQWF4bn4o9RrcSBE",{"id":87,"extension":5,"links":88,"meta":668,"stem":669,"__hash__":670},"urlSettings\u002Fdata\u002Fshared\u002Furls.yml",[89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,169,173,177,181,185,189,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256,260,264,268,272,276,280,284,288,292,296,300,303,307,311,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446,450,454,458,461,465,469,473,477,481,485,488,491,494,497,501,505,508,512,516,520,524,528,532,536,540,544,548,552,556,559,563,567,571,575,579,582,585,588,592,595,599,603,607,611,614,618,622,625,628,631,635,639,643,646,649,652,656,660,664],{"key":90,"label":91,"href":92},"downloads.desktop","Desktop download page","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdownload",{"key":94,"label":95,"href":96},"downloads.macOS.dmgArm64","macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg-arm64\u002Fdownload",{"key":98,"label":99,"href":100},"downloads.macOS.dmgIntel","macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg\u002Fdownload",{"key":102,"label":103,"href":104},"downloads.macOS.pkg","macOS PKG","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg\u002Fdownload",{"key":106,"label":107,"href":108},"downloads.macOS.universal","Desktop macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fmacos-universal\u002Fdownload",{"key":110,"label":111,"href":112},"downloads.macOS.pkgArm64","Desktop macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd-arm64\u002Fdownload",{"key":114,"label":115,"href":116},"downloads.macOS.pkgIntel","Desktop macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd\u002Fdownload",{"key":118,"label":119,"href":120},"downloads.windows.appinstaller","Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fpieces_for_x.appinstaller",{"key":122,"label":123,"href":124},"downloads.windows.exe","Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-exe\u002Fdownload",{"key":126,"label":127,"href":128},"downloads.windows.msix","Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-msix\u002Fdownload",{"key":130,"label":131,"href":132},"downloads.windows.suiteManager","Windows Suite Manager","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_suite_windows\u002Fappinstaller\u002Fdownload",{"key":134,"label":135,"href":136},"downloads.linux.flatpakRepo","Linux Flatpak repository","https:\u002F\u002Fbuilds.pieces.app\u002Fpieces-flatpak-repo\u002Fpieces-flatpak.flatpakrepo",{"key":138,"label":139,"href":140},"downloads.linux.snapDesktop","Linux Snap Desktop","https:\u002F\u002Fsnapcraft.io\u002Fpieces-for-developers",{"key":142,"label":143,"href":144},"downloads.linux.snapPiecesOS","Linux Snap PiecesOS","https:\u002F\u002Fsnapcraft.io\u002Fpieces-os",{"key":146,"label":147,"href":148},"downloads.linux.snap","Desktop Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fsnap\u002Fdownload",{"key":150,"label":151,"href":152},"downloads.piecesOS.macOS.dmgArm64","PiecesOS macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg-arm64\u002Fdownload",{"key":154,"label":155,"href":156},"downloads.piecesOS.macOS.dmgIntel","PiecesOS macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg\u002Fdownload",{"key":158,"label":159,"href":160},"downloads.piecesOS.macOS.universal","PiecesOS macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fmacos-universal\u002Fdownload",{"key":162,"label":163,"href":164},"downloads.piecesOS.macOS.pkgArm64","PiecesOS macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only-arm64\u002Fdownload",{"key":166,"label":167,"href":168},"downloads.piecesOS.macOS.pkgIntel","PiecesOS macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only\u002Fdownload",{"key":170,"label":171,"href":172},"downloads.piecesOS.windows.appinstaller","PiecesOS Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fos_server.appinstaller",{"key":174,"label":175,"href":176},"downloads.piecesOS.windows.exe","PiecesOS Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-exe\u002Fdownload",{"key":178,"label":179,"href":180},"downloads.piecesOS.windows.msix","PiecesOS Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-msix\u002Fdownload",{"key":182,"label":183,"href":184},"downloads.piecesOS.linux.snap","PiecesOS Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fsnap\u002Fdownload",{"key":186,"label":187,"href":188},"downloads.combined.macOS.appleSilicon","Combined macOS installer Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-arm64\u002Fdownload",{"key":190,"label":191,"href":104},"downloads.combined.macOS.intel","Combined macOS installer Intel",{"key":193,"label":194,"href":195},"downloads.guides.macOS","macOS installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fmacos-installation-guide",{"key":197,"label":198,"href":199},"downloads.guides.windows","Windows installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fwindows-installation-guide",{"key":201,"label":202,"href":203},"downloads.guides.linux","Linux installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide",{"key":205,"label":206,"href":207},"downloads.guides.linuxFlatpak","Linux Flatpak installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide\u002Fflatpak",{"key":209,"label":210,"href":211},"downloads.guides.linuxSnap","Linux Snap installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide\u002Fsnap",{"key":213,"label":214,"href":215},"downloads.guides.piecesOS","PiecesOS manual installation","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fmanual-installation",{"key":217,"label":218,"href":219},"extensions.chrome","Chrome extension","https:\u002F\u002Fchrome.google.com\u002Fwebstore\u002Fdetail\u002Fpieces-save-code-snippets\u002Figbgibhbfonhmjlechmeefimncpekepm",{"key":221,"label":222,"href":223},"extensions.firefox","Firefox add-on","https:\u002F\u002Faddons.mozilla.org\u002Fen-US\u002Ffirefox\u002Faddon\u002Fpieces-save-code-from-the-web\u002F",{"key":225,"label":226,"href":227},"extensions.edge","Edge add-on","https:\u002F\u002Fmicrosoftedge.microsoft.com\u002Faddons\u002Fdetail\u002Fpieces-save-code-snippet\u002Fhglfimcdgonaeeobjckfdabcldfidmim",{"key":229,"label":230,"href":231},"extensions.vscode","VS Code extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.pieces-vscode",{"key":233,"label":234,"href":235},"extensions.visualStudio","Visual Studio extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.PiecesVisualStudio",{"key":237,"label":238,"href":239},"extensions.jetbrains","JetBrains plugin","https:\u002F\u002Fplugins.jetbrains.com\u002Fplugin\u002F17328-pieces--save-search-share--reuse-code-snippets",{"key":241,"label":242,"href":243},"extensions.obsidian","Obsidian plugin","https:\u002F\u002Fobsidian.md\u002Fplugins?id=pieces-for-developers",{"key":245,"label":246,"href":247},"extensions.sublime","Sublime package","https:\u002F\u002Fpackagecontrol.io\u002Fpackages\u002FPieces",{"key":249,"label":250,"href":251},"extensions.neovim","Neovim plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neo_vim",{"key":253,"label":254,"href":255},"extensions.jupyterlab","JupyterLab plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fjupyterlab-pieces",{"key":257,"label":258,"href":259},"extensions.cli","Pieces CLI","https:\u002F\u002Fpypi.org\u002Fproject\u002Fpieces-cli\u002F",{"key":261,"label":262,"href":263},"docs.home","Documentation home","https:\u002F\u002Fdocs.pieces.app",{"key":265,"label":266,"href":267},"docs.getStarted","Get started docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces",{"key":269,"label":270,"href":271},"docs.api","API docs","https:\u002F\u002Fdocs.pieces.app\u002Fapi",{"key":273,"label":274,"href":275},"docs.desktop.overview","Desktop overview","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop",{"key":277,"label":278,"href":279},"docs.desktop.onboarding","Desktop onboarding","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fonboarding",{"key":281,"label":282,"href":283},"docs.desktop.timeline","Desktop timeline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Ftimeline",{"key":285,"label":286,"href":287},"docs.desktop.summaries","Desktop summaries docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fsingle-click-summaries",{"key":289,"label":290,"href":291},"docs.desktop.search","Desktop conversational search docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconversational-search",{"key":293,"label":294,"href":295},"docs.desktop.drive","Desktop drive docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdrive",{"key":297,"label":298,"href":299},"docs.desktop.account","Desktop account settings docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconfiguration\u002Faccount",{"key":301,"label":302,"href":92},"docs.desktop.download","Desktop download docs",{"key":304,"label":305,"href":306},"docs.piecesOS.overview","PiecesOS overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies",{"key":308,"label":309,"href":310},"docs.piecesOS.details","PiecesOS details docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os",{"key":312,"label":313,"href":215},"docs.piecesOS.install","PiecesOS install docs",{"key":315,"label":316,"href":317},"docs.piecesOS.quickMenu","PiecesOS quick menu docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fquick-menu",{"key":319,"label":320,"href":321},"docs.piecesOS.storage","On-device storage docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fon-device-storage",{"key":323,"label":324,"href":325},"docs.piecesOS.troubleshooting","PiecesOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Ftroubleshooting",{"key":327,"label":328,"href":329},"docs.mcp.overview","MCP overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp",{"key":331,"label":332,"href":333},"docs.mcp.cursor","MCP Cursor docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcursor",{"key":335,"label":336,"href":337},"docs.mcp.vscode","MCP VS Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fvs-code",{"key":339,"label":340,"href":341},"docs.mcp.claudeDesktop","MCP Claude Desktop docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-desktop",{"key":343,"label":344,"href":345},"docs.mcp.claudeCode","MCP Claude Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-code",{"key":347,"label":348,"href":349},"docs.mcp.claudeCowork","MCP Claude Cowork docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-cowork",{"key":351,"label":352,"href":353},"docs.mcp.githubCopilot","MCP GitHub Copilot docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgithub-copilot",{"key":355,"label":356,"href":357},"docs.mcp.goose","MCP Goose docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoose",{"key":359,"label":360,"href":361},"docs.mcp.windsurf","MCP Windsurf docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fwindsurf",{"key":363,"label":364,"href":365},"docs.mcp.zed","MCP Zed docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fzed",{"key":367,"label":368,"href":369},"docs.mcp.jetbrains","MCP JetBrains docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fjetbrains-ides",{"key":371,"label":372,"href":373},"docs.mcp.continueDev","MCP Continue docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcontinue-dev",{"key":375,"label":376,"href":377},"docs.mcp.cline","MCP Cline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcline",{"key":379,"label":380,"href":381},"docs.mcp.raycast","MCP Raycast docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fraycast",{"key":383,"label":384,"href":385},"docs.mcp.rovoDevCli","MCP Rovo Dev CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Frovo-dev-cli",{"key":387,"label":388,"href":389},"docs.mcp.openaiCodexCli","MCP OpenAI Codex CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenai-codex-cli",{"key":391,"label":392,"href":393},"docs.mcp.googleGeminiCli","MCP Google Gemini CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoogle-gemini-cli",{"key":395,"label":396,"href":397},"docs.mcp.amazonQ","MCP Amazon Q docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Famazon-q-developer",{"key":399,"label":400,"href":401},"docs.mcp.chatgptDev","MCP ChatGPT Developer Mode docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fchatgpt-developer-mode",{"key":403,"label":404,"href":405},"docs.mcp.openclaw","MCP OpenClaw docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenclaw",{"key":407,"label":408,"href":409},"docs.mcp.mcpRemote","MCP Remote docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fmcp-remote",{"key":411,"label":412,"href":413},"docs.mcp.ngrok","MCP ngrok docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fngrok-setup",{"key":415,"label":416,"href":417},"docs.troubleshooting.macOS","macOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fmacos",{"key":419,"label":420,"href":421},"docs.troubleshooting.windows","Windows troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fwindows",{"key":423,"label":424,"href":425},"docs.troubleshooting.linux","Linux troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Flinux",{"key":427,"label":428,"href":429},"docs.privacy","Privacy and security docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fprivacy-security-your-data",{"key":431,"label":432,"href":433},"docs.support","Support docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fsupport",{"key":435,"label":436,"href":437},"portal.home","Pieces portal","https:\u002F\u002Fportal.pieces.app",{"key":439,"label":440,"href":441},"site.home","Website home","https:\u002F\u002Fpieces.app",{"key":443,"label":444,"href":445},"site.about","About page","https:\u002F\u002Fpieces.app\u002Fabout",{"key":447,"label":448,"href":449},"site.features","Features page","https:\u002F\u002Fpieces.app\u002Ffeatures",{"key":451,"label":452,"href":453},"site.plugins","Plugins page","https:\u002F\u002Fpieces.app\u002Fplugins",{"key":455,"label":456,"href":457},"site.contact","Contact page","https:\u002F\u002Fpieces.app\u002Fcontact",{"key":459,"label":58,"href":460},"site.updates","https:\u002F\u002Fpieces.app\u002Fupdates",{"key":462,"label":463,"href":464},"site.news","News","https:\u002F\u002Fpieces.app\u002Fnews",{"key":466,"label":467,"href":468},"site.events","Community events","https:\u002F\u002Fpieces.app\u002Fcommunity\u002Fevents",{"key":470,"label":471,"href":472},"site.userStories","User stories","https:\u002F\u002Fpieces.app\u002Fuser-stories",{"key":474,"label":475,"href":476},"site.academy","Academy","https:\u002F\u002Fpieces.app\u002Flearn\u002Facademy",{"key":478,"label":479,"href":480},"site.support","Website support","https:\u002F\u002Fpieces.app\u002Fsupport",{"key":482,"label":483,"href":484},"site.standup","Standup","https:\u002F\u002Fpieces.app\u002Fstandup",{"key":486,"label":34,"href":487},"site.blog","https:\u002F\u002Fcode.pieces.app\u002Fblog",{"key":489,"label":43,"href":490},"social.discord","https:\u002F\u002Fdiscord.gg\u002Fgetpieces",{"key":492,"label":46,"href":493},"social.x","https:\u002F\u002Fx.com\u002Fgetpieces",{"key":495,"label":496,"href":493},"social.twitter","Twitter",{"key":498,"label":499,"href":500},"social.instagram","Instagram","https:\u002F\u002Fwww.instagram.com\u002Fgetpieces\u002F",{"key":502,"label":503,"href":504},"social.tiktok","TikTok","https:\u002F\u002Fwww.tiktok.com\u002F@getpieces",{"key":506,"label":49,"href":507},"social.linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fgetpieces\u002F",{"key":509,"label":510,"href":511},"social.youtube","YouTube","https:\u002F\u002Fyoutube.com\u002F@getpieces",{"key":513,"label":514,"href":515},"github.org","GitHub organization","https:\u002F\u002Fgithub.com\u002Fpieces-app",{"key":517,"label":518,"href":519},"github.support","GitHub support","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport",{"key":521,"label":522,"href":523},"github.issues","GitHub issues","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fissues",{"key":525,"label":526,"href":527},"github.discussions","GitHub discussions","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fdiscussions",{"key":529,"label":530,"href":531},"github.documentation","GitHub documentation","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fdocumentation",{"key":533,"label":534,"href":535},"github.opensource","GitHub open source","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fopensource",{"key":537,"label":538,"href":539},"github.sdks.python","Python SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-python",{"key":541,"label":542,"href":543},"github.sdks.typescript","TypeScript SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-typescript",{"key":545,"label":546,"href":547},"github.sdks.dart","Dart SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-dart",{"key":549,"label":550,"href":551},"github.sdks.kotlin","Kotlin SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-kotlin",{"key":553,"label":554,"href":555},"github.plugins.obsidian","Obsidian plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fobsidian-pieces",{"key":557,"label":558,"href":255},"github.plugins.jupyterlab","JupyterLab plugin repository",{"key":560,"label":561,"href":562},"github.plugins.sublime","Sublime plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_sublime",{"key":564,"label":565,"href":566},"github.plugins.neovim","Neovim plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neovim",{"key":568,"label":569,"href":570},"github.cliAgent","CLI agent repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fcli-agent",{"key":572,"label":573,"href":574},"github.mcpDart","MCP Dart repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fmcp_dart",{"key":576,"label":577,"href":578},"github.awesomePieces","Awesome Pieces repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fawesome-pieces",{"key":580,"label":581,"href":66},"legal.privacyPolicy","Privacy policy",{"key":583,"label":584,"href":69},"legal.refundPolicy","Refund policy",{"key":586,"label":587,"href":72},"legal.terms","Terms",{"key":589,"label":590,"href":591},"legal.security","Legal security","https:\u002F\u002Fpieces.app\u002Flegal\u002Fsecurity",{"key":593,"label":594,"href":511},"videos.youtubeChannel","YouTube channel",{"key":596,"label":597,"href":598},"videos.gettingStartedDesktop","Getting started desktop video","https:\u002F\u002Fyoutu.be\u002FdUr1lRM_TYk",{"key":600,"label":601,"href":602},"videos.snippetDiscoveryxR","Snippet discovery video","https:\u002F\u002Fyoutu.be\u002FG6vb1USw-30",{"key":604,"label":605,"href":606},"sales.bookACall","Book a sales call","https:\u002F\u002Fcalendar.app.google\u002FWVUDtUfNy5Vst3sH7",{"key":608,"label":609,"href":610},"sales.enterprise","Enterprise form","https:\u002F\u002Fgetpieces.typeform.com\u002Fto\u002FaVQFTvpE",{"key":612,"label":613,"href":527},"sales.feedback","Feedback discussions",{"key":615,"label":616,"href":617},"sales.earlyAccess","Early access form","https:\u002F\u002Fgetpieces.typeform.com\u002Fearlyaccess",{"key":619,"label":620,"href":621},"sales.supportEmail","Support email","mailto:support@pieces.app",{"key":623,"label":624,"href":19},"routes.home","Home route",{"key":626,"label":627,"href":56},"routes.about","About route",{"key":629,"label":630,"href":12},"routes.downloads","Downloads route",{"key":632,"label":633,"href":634},"routes.thanks","Post-install thanks route","\u002Finstall\u002Fthanks",{"key":636,"label":637,"href":638},"routes.pricing","Pricing route","\u002Fpricing",{"key":640,"label":641,"href":642},"cta.freeTrial","Start free trial CTA (Pieces Pro) — used by \u002Fcampaigns\u002F* landing pages","https:\u002F\u002Fcampaigns.pieces.app\u002F",{"key":644,"label":645,"href":22},"routes.enterprise","Enterprise route",{"key":647,"label":648,"href":62},"routes.contact","Contact route",{"key":650,"label":651,"href":59},"routes.updates","Updates route",{"key":653,"label":654,"href":655},"routes.migrationError","Migration error route","\u002Fmigration\u002Ferror",{"key":657,"label":658,"href":659},"routes.authenticated","Post-login authenticated route","\u002Fauth\u002Fsigned-in",{"key":661,"label":662,"href":663},"routes.signed-out","Signed out route","\u002Fauth\u002Fsigned-out",{"key":665,"label":666,"href":667},"routes.authentication-error","Authentication error route","\u002Fauth\u002Ferror",{},"data\u002Fshared\u002Furls","2AvfSWI6bZACH5Kr1ZS3txMLjteRjCjbDR_ul1uRZ9Q",{"id":672,"title":673,"author":674,"authorPhoto":675,"authorPhotoAlt":676,"authorSlug":677,"body":678,"buttonText":1196,"buttonUrl":1197,"category":1198,"date":1199,"description":1200,"draft":1201,"editorsPick":1201,"extension":1202,"featured":32,"image":1203,"imageAlt":676,"meta":1204,"navigation":32,"ogImage":1205,"ogImageAlt":676,"path":1206,"seo":1207,"stem":1208,"tags":676,"__hash__":1209},"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":679,"value":680,"toc":1175},"minimark",[681,693,706,718,721,744,749,757,767,770,776,783,787,790,804,808,819,825,834,838,844,850,864,871,875,887,892,898,904,908,914,919,923,929,934,938,941,947,950,983,994,998,1001,1007,1010,1016,1022,1026,1033,1039,1043,1049,1055,1058,1078,1082,1085,1091,1094,1097,1114,1117,1121,1124,1130,1134,1140,1161,1167],[682,683,684,685,692],"p",{},"Welcome back! In ",[686,687,691],"a",{"href":688,"rel":689},"https:\u002F\u002Fpieces.app\u002Fblog\u002Fbuilding-daily-standup-generator-with-pieces-api-sdk",[690],"nofollow","Part 1,"," we built a complete PiecesOS service that:",[694,695,696,700,703],"ul",{},[697,698,699],"li",{},"Connects to PiecesOS and maintains a WebSocket connection",[697,701,702],{},"Fetches and caches workstream summaries grouped by day",[697,704,705],{},"Extracts the summary content from annotations",[682,707,708,709,713,714,717],{},"Now we have all of the infrastructure in place. But here's the thing: having raw summaries with their content is ",[710,711,712],"em",{},"cool",", but it's not exactly... useful. I mean, I have all this text about what I did, but what did I actually ",[710,715,716],{},"accomplish"," today?",[682,719,720],{},"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:",[694,722,723,729,734,739],{},[697,724,725],{},[726,727,728],"strong",{},"What did I work on?",[697,730,731],{},[726,732,733],{},"Which projects did I touch?",[697,735,736],{},[726,737,738],{},"Who did I collaborate with?",[697,740,741],{},[726,742,743],{},"What should I remember for tomorrow?",[745,746,748],"h2",{"id":747},"the-challenge","The challenge",[682,750,751,752,756],{},"Thanks to Part 1, we now have access to rich summary data using ",[753,754,755],"code",{},"SummaryWithContent",":",[758,759,764],"pre",{"className":760,"code":762,"language":763},[761],"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",[753,765,762],{"__ignoreMap":766},"",[682,768,769],{},"This is great! But it's still just raw text. What we want are structured and actionable insights:",[758,771,774],{"className":772,"code":773,"language":763},[761],"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",[753,775,773],{"__ignoreMap":766},[682,777,778,779,782],{},"See the difference? One is data, the other is ",[726,780,781],{},"information",".",[745,784,786],{"id":785},"enter-gemini","Enter Gemini",[682,788,789],{},"Google's Gemini API is perfect for this. It can:",[694,791,792,795,798,801],{},[697,793,794],{},"Understand natural language",[697,796,797],{},"Extract structured information",[697,799,800],{},"Return JSON (which is exactly what we need!)",[697,802,803],{},"Process multiple summaries at once",[745,805,807],{"id":806},"setting-up","Setting up",[682,809,810,811,814,815,818],{},"First, add the Gemini SDK to ",[753,812,813],{},"pubspec.yaml"," below the ‘",[753,816,817],{},"git:","’ dependency:",[758,820,823],{"className":821,"code":822,"language":763},[761],"dependencies:\n  google_generative_ai: ^0.4.6\n",[753,824,822],{"__ignoreMap":766},[682,826,827,828,833],{},"You'll also need an API key. Get one from ",[686,829,832],{"href":830,"rel":831},"https:\u002F\u002Fmakersuite.google.com\u002Fapp\u002Fapikey",[690],"Google AI Studio"," – it's free for reasonable usage!",[745,835,837],{"id":836},"building-the-daily-recap-service","Building the daily recap service",[682,839,840,841,782],{},"Let's create a new service: ",[753,842,843],{},"lib\u002Fservices\u002Fdaily_recap_service.dart",[758,845,848],{"className":846,"code":847,"language":763},[761],"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",[753,849,847],{"__ignoreMap":766},[694,851,852,858],{},[697,853,854,857],{},[726,855,856],{},"gemini-2.5-flash-lite",": faster and more cost-effective",[697,859,860,863],{},[726,861,862],{},"temperature: 0.7",": Not too creative, not too rigid",[682,865,866,867,870],{},"Now, let's build the ",[753,868,869],{},"generateDailyRecap"," function piece by piece.",[745,872,874],{"id":873},"the-prompt-engineering","The prompt engineering",[682,876,877,882,883,886],{},[686,878,881],{"href":879,"rel":880},"https:\u002F\u002Fpieces.app\u002Fblog\u002Fllm-prompt-engineering",[690],"Crafting the right prompt"," is ",[726,884,885],{},"an art",". Here are some important tips:",[888,889,891],"h3",{"id":890},"avoid-vague-prompts","Avoid vague prompts",[758,893,896],{"className":894,"code":895,"language":763},[761],"Analyze these summaries and tell me what I did today.\n",[753,897,895],{"__ignoreMap":766},[682,899,900,903],{},[726,901,902],{},"Result:"," Always try to be specific. AI does not read your mind… yet! (Pieces does read your mind, but whatever 😉)",[888,905,907],{"id":906},"better-structure","Better structure",[758,909,912],{"className":910,"code":911,"language":763},[761],"Return JSON with: summary, projects, people.\n",[753,913,911],{"__ignoreMap":766},[682,915,916,918],{},[726,917,902],{}," Always say what do you expect the AI to return to be able to correctly parse it:",[888,920,922],{"id":921},"show-some-examples","Show some examples",[758,924,927],{"className":925,"code":926,"language":763},[761],"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",[753,928,926],{"__ignoreMap":766},[682,930,931,933],{},[726,932,902],{}," AI is similar to humans; the best way to understand is by examples.",[888,935,937],{"id":936},"our-beautiful-prompt","Our beautiful prompt",[682,939,940],{},"Here's the final prompt we’ll use:",[758,942,945],{"className":943,"code":944,"language":763},[761],"\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",[753,946,944],{"__ignoreMap":766},[682,948,949],{},"Why this works:",[951,952,953,959,965,971,977],"ol",{},[697,954,955,958],{},[726,956,957],{},"Clear role",": \"You are an AI assistant...\"",[697,960,961,964],{},[726,962,963],{},"Specific format",": Exact JSON structure",[697,966,967,970],{},[726,968,969],{},"Examples",": Shows what we want",[697,972,973,976],{},[726,974,975],{},"Constraints",": \"Don't make things up\", \"Empty arrays if no data\"",[697,978,979,982],{},[726,980,981],{},"Enum values",": Explicit status options",[682,984,985,986,989,990,993],{},"These two helper methods,",[753,987,988],{},"_buildPrompt"," and ",[753,991,992],{},"_buildSummariesContext"," (we'll see next), are what power our analysis. But where do they fit in the actual application?",[745,995,997],{"id":996},"sending-rich-context-to-gemini","Sending rich context to Gemini",[682,999,1000],{},"Now that we have the actual summary content, we can build a rich prompt:",[758,1002,1005],{"className":1003,"code":1004,"language":763},[761]," \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",[753,1006,1004],{"__ignoreMap":766},[682,1008,1009],{},"This formats each summary with structured labels and metadata, giving Gemini way more context to work with",[682,1011,1012,1013],{},"Let’s add an empty factory method to create an empty ",[753,1014,1015],{},"DailyRecapData",[758,1017,1020],{"className":1018,"code":1019,"language":763},[761],"\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",[753,1021,1019],{"__ignoreMap":766},[745,1023,1025],{"id":1024},"handling-the-response","Handling the Response",[682,1027,1028,1029,1032],{},"Gemini returns JSON (because we set ",[753,1030,1031],{},"responseMimeType","), so parsing is straightforward:",[758,1034,1037],{"className":1035,"code":1036,"language":763},[761],"\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",[753,1038,1036],{"__ignoreMap":766},[745,1040,1042],{"id":1041},"putting-it-all-together-the-complete-generatedailyrecap-function","Putting it all together: the complete generateDailyRecap function",[682,1044,1045,1046,1048],{},"Now that we've seen all the pieces, here's how they fit together in the actual ",[753,1047,869],{}," function (how yours should look 😉):",[758,1050,1053],{"className":1051,"code":1052,"language":763},[761],"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",[753,1054,1052],{"__ignoreMap":766},[682,1056,1057],{},"See how it flows?",[951,1059,1060,1063,1066,1069,1072,1075],{},[697,1061,1062],{},"Check for empty summaries",[697,1064,1065],{},"Build the context string from all summaries",[697,1067,1068],{},"Create the prompt with instructions",[697,1070,1071],{},"Send to Gemini",[697,1073,1074],{},"Parse the JSON response",[697,1076,1077],{},"Return structured data (or throw error)",[745,1079,1081],{"id":1080},"the-data-models","The data models",[682,1083,1084],{},"I created clean data classes to work with:",[758,1086,1089],{"className":1087,"code":1088,"language":763},[761],"\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",[753,1090,1088],{"__ignoreMap":766},[682,1092,1093],{},"This gives us type safety and makes it easy to work with the data later.",[682,1095,1096],{},"Look at what Gemini did:",[694,1098,1099,1102,1105,1108,1111],{},[697,1100,1101],{},"✅ Understood that I was working on \"Pieces OS Integration\"",[697,1103,1104],{},"✅ Correctly identified it as \"completed\"",[697,1106,1107],{},"✅ Extracted actual reminders from my work",[697,1109,1110],{},"✅ Pulled out technical notes I discovered",[697,1112,1113],{},"✅ Wrote a coherent summary of the day",[682,1115,1116],{},"And it did all this from just timestamps and titles!",[888,1118,1120],{"id":1119},"real-world-example-what-gemini-generated","Real-world example: what Gemini generated",[682,1122,1123],{},"Here's an actual JSON response that Gemini generated from my workstream summaries:",[758,1125,1128],{"className":1126,"code":1127,"language":763},[761],"{\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",[753,1129,1127],{"__ignoreMap":766},[745,1131,1133],{"id":1132},"complete-reference-implementation","Complete reference implementation",[682,1135,1136,1137,1139],{},"For your reference, here's the complete ",[753,1138,843],{}," file with everything we've built:",[694,1141,1142,1145,1151,1156],{},[697,1143,1144],{},"The service initialization with Gemini configuration",[697,1146,1147,1148,1150],{},"The ",[753,1149,869],{}," function that orchestrates everything",[697,1152,1147,1153,1155],{},[753,1154,992],{}," helper for formatting summaries",[697,1157,1147,1158,1160],{},[753,1159,988],{}," helper for crafting the AI prompt",[758,1162,1165],{"className":1163,"code":1164,"language":763},[761],"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",[753,1166,1164],{"__ignoreMap":766},[682,1168,1169,1174],{},[686,1170,1173],{"href":1171,"rel":1172},"https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fblog-dart-daily-stand-up-generator",[690],"Reference GitHub"," to view the full project.",{"title":766,"searchDepth":1176,"depth":1176,"links":1177},2,[1178,1179,1180,1181,1182,1189,1190,1191,1192,1195],{"id":747,"depth":1176,"text":748},{"id":785,"depth":1176,"text":786},{"id":806,"depth":1176,"text":807},{"id":836,"depth":1176,"text":837},{"id":873,"depth":1176,"text":874,"children":1183},[1184,1186,1187,1188],{"id":890,"depth":1185,"text":891},3,{"id":906,"depth":1185,"text":907},{"id":921,"depth":1185,"text":922},{"id":936,"depth":1185,"text":937},{"id":996,"depth":1176,"text":997},{"id":1024,"depth":1176,"text":1025},{"id":1041,"depth":1176,"text":1042},{"id":1080,"depth":1176,"text":1081,"children":1193},[1194],{"id":1119,"depth":1185,"text":1120},{"id":1132,"depth":1176,"text":1133},"Get started with Pieces","https:\u002F\u002Fpieces.app\u002F","AI & LLMs","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",{},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fopen-graph\u002Fblog\u002Fbuilding-pieces-productivity-app-with-gemini-ai.png","\u002Fblog\u002Fbuilding-pieces-productivity-app-with-gemini-ai",{"title":673,"description":1200},"blog\u002Fbuilding-pieces-productivity-app-with-gemini-ai","_AF5q9CA_zjHkYtpP1MCZdKtjp89cnHPsfDEJaGHu8A",{"id":1211,"title":674,"body":1212,"description":1216,"draft":1201,"extension":1202,"meta":1219,"navigation":32,"path":1220,"photo":1221,"photoAlt":676,"seo":1222,"stem":1223,"__hash__":1224},"authors\u002Fauthors\u002Fbishoy-hany.md",{"type":679,"value":1213,"toc":1217},[1214],[682,1215,1216],{},"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":766,"searchDepth":1176,"depth":1176,"links":1218},[],{},"\u002Fauthors\u002Fbishoy-hany","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fauthors\u002Fbishoy-hany.jpg",{"title":674,"description":1216},"authors\u002Fbishoy-hany","_m1q8mqNk1I4j1V0_YJSK0zuMS48DBT4Nqw9e3PZjMM",{"left":1226,"top":1226,"width":1227,"height":1227,"rotate":1226,"vFlip":1201,"hFlip":1201,"body":1228},0,24,"\u003Cpath fill=\"currentColor\" d=\"m7.825 13l4.9 4.9q.3.3.288.7t-.313.7q-.3.275-.7.288t-.7-.288l-6.6-6.6q-.15-.15-.213-.325T4.426 12t.063-.375t.212-.325l6.6-6.6q.275-.275.688-.275t.712.275q.3.3.3.713t-.3.712L7.825 11H19q.425 0 .713.288T20 12t-.288.713T19 13z\"\u002F>"]