# llms-full.txt for Tiles Privacy Expanded full-text context for tiles.run, intended for larger context windows. Source site: https://tiles.run Generated: 2026-11-08T17:07:16.097Z Canonical index file: /llms.txt Also available at: /.well-known/llms-full.txt ================================================================================ ## Homepage (https://tiles.run/) Tiles A local-first, collaborative AI assistant that works for you. Built with open models and decentralized protocols. Backed by Mozilla Foundation: https://www.mozillafoundation.org/en/what-we-do/grantmaking/incubator/human-scale-ai/cohort/ Hero subtext: For sensitive knowledge work or personal tasks, your AI shouldn’t require trusting a third party with your conversations and intellectual property. Run models locally, sync chats P2P, and use social features built on AT Protocol. Tiles gives you user-owned keys for your digital life with DIDs and UCANs, so your data and identity truly remain yours. Current status: Public alpha for macOS and Linux. Feature: Use local models on remote devices with `tiles remote share`; start the remote inference server with `tiles server start`, generate a share ticket, then run `tiles --remote ` on the device intending to use remote inference. Feature (coming soon): Every chat is a sandbox — resume or share chats as sandboxed environments with friends or agents across devices. Why Tiles: sensitive knowledge work stays private on your machines, with secure collaboration built in; out-of-the-box on first open without API keys, model or harness selection, sync sessions and work across devices without leaking data to a cloud vendor, share chats publicly or privately without copy-pasting threads elsewhere, sovereignty over your online identity and data with DID and UCAN for local control and ATproto for social features, use models on remote machines as if they were local, Offline Installer bundles the model for air-gapped use. Use cases: Individuals plan finances, track health notes, and journal privately, run models locally, sync across devices, and share only when they choose. Coworking spaces turn shared compute into private AI infrastructure so members can use local models from their own devices while keeping identity and data private. Researchers review literature, analyze datasets, and run agents in preconfigured, resumable research sandboxes. Enterprises deploy private agentic systems powered by open frontier models, secure users and agents with zero-trust authentication and authorization, simplify team management, and reduce infrastructure and model costs. Platform support: Apple Silicon, Linux. ================================================================================ ## Download (https://tiles.run/download) macOS: The network and offline installers include only the CLI. The Canary version includes a desktop app and a menu bar app. Network installer for macOS: https://download.tiles.run/tiles-0.4.19-signed.pkg Version: 0.4.19 Size: 96.58 MB SHA256: f270d0c5cfb0b1f93179fbb1978b2d3c2b398bf0eb508ec8cd86fc6766f84a34 Offline installer for macOS (bundled model: gpt-oss-20b-MXFP4-Q4): https://download.tiles.run/tiles-0.4.17-full-signed.pkg Size: 7.02 GB SHA256: bdf9dc950ed40695ef5434776d7a757cff902d9fc5c6961ee301eadf004ce7e9 SHA256 file: https://download.tiles.run/checksums/tiles-0.4.17-full-signed.pkg.sha256 Canary downloads and release notes: https://github.com/tilesprivacy/tiles/releases/tag/canary Nightly builds for developers who want the latest Tiles features. Available for macOS and Linux. Canary can be unstable. Linux: Install the canary version with curl -LsSf https://tiles.run/install.sh | sh -s -- --canary. The offline installer for Linux is a work in progress. tiles-canary.pkg: https://github.com/tilesprivacy/tiles/releases/download/canary/tiles-canary.pkg Tiles canary New - Linux canary. Install it with `curl -LsSf https://www.tiles.run/install.sh | sh -s -- --canary`, and open the chat in your browser at http://127.0.0.1:1729. - One Linux tarball for every GPU: CUDA 12, CUDA 13 and Vulkan ship together, and the right one is picked at runtime. - Onboarding in the app: sign in, optionally connect your ATmosphere account, then pick a model. - Choose from the Gemma 4 lineup (E2B, E4B, 12B, 26B-A4B, 31B), with a recommendation that fits this machine's memory. - Model downloads show progress, can be paused, and resume where they stopped. You can explore the app while one runs. - A Models page in the sidebar to download, resume and switch models. - Manage plugins from the plugins page: install, remove, enable and disable. Changes reload the agent on their own, with the model kept loaded. - The chat bar names the running model. - Faster first reply: the model loads and the agent prompt is prefilled as soon as inference starts. - Report an error from the chat, with a log tail that carries no conversation text. - Tool calls fold into the reasoning block they ran under. - The CLI asks before the first model download, and downloads through the daemon, so they resume too. - tiles:// links open in the app. - Keep the Mac awake with the lid closed. - macOS menu bar app. It starts the daemon, shows your ATmosphere account, and opens the chat window. - Chat from the app. The bundled chat UI talks to the daemon over new APIs with streamed responses. - Share a chat to the ATmosphere from the app, with a link anyone can open. - Shared chats now keep the full story: model info, reasoning traces, and tool calls, built from what the agent reported. - Edit the modelfile from the app settings and reload the agent without a restart. - Keep awake toggle in the menu bar. Changed - Logs and error strings no longer carry conversation text. Fixed - The packaged app can save the modelfile. - When llama refuses to load a model, it says why. - Pi's tools run with a PATH that can find what's installed. - Avatars in the chat UI load through the daemon. - A canary build is no longer offered the stable release it was cut after as an update. - Sharing a session that was started from the app. - DNS resolution when a nameserver has an interface scope. - Quitting from the dock, and the dock icon reopening the window. Build - Every push to the canary branch publishes a fresh Linux build here, replacing the last one. - The app bundle now takes the latest chat UI at build time, so UI work ships without a pin bump. - Packaging no longer leaves a stray Tiles.app behind. ================================================================================ ## Plugins (https://tiles.run/plugins) Tiles supports the open Agent Plugins standard for portable workflow plugins: https://agent-plugins.org/. Agent Plugins use a root plugin.json manifest and can include Agent Skills under skills/, MCP servers in mcp.json, and client-specific extensions in reverse-domain directories. Current install pattern: tiles plugin install https://download.tiles.run/plugins/caldir.zip Plugins are distributed as zip files under https://download.tiles.run/plugins/. ================================================================================ ## Mission (https://tiles.run/mission) Our mission is to build software that gives people greater agency, control, and choice in their digital lives. Tiles Privacy was born from the User & Agents community with a simple idea: software should understand you without taking anything from you. Tiles focuses on privacy-focused engineering and practical consumer experience. ================================================================================ ## Help (https://tiles.run/help) Get help Find the shortest path from stuck to moving again. Documentation: install Tiles, read the manual, check Tilekit docs, and get unstuck on setup. GitHub Issues: report reproducible bugs, request features, and track fixes in the open. Discord: fast async help from users and maintainers when you need a quick route forward. Support FAQ: include Tiles version, operating system version, exact output, screenshots if useful, and the shortest reproduction steps for bug reports. Feature requests should include workflow context, current workaround, and the outcome you want. Discord is used because the team is doing what it can with what it has, meeting people on their level while building something better. Releases has all versions and download links. Download has the latest version. Status has service availability. ================================================================================ ## Press Kit (https://tiles.run/press-kit) Tiles press kit Editorial summary, brand files, screenshots, company details, and contact details for writing about Tiles. A local-first, collaborative AI assistant that works for you. Built with open models and decentralized protocols. Tiles runs open models on your own device, so your conversations and data stay with you. Peer-to-peer encrypted sync connects your devices without a central server, and social features are built on the AT Protocol. Identity is user-owned through locally generated DIDs and UCANs, so your data and identity remain yours. Tiles is in public alpha for macOS and Linux. It is built by Tiles Privacy Technologies Pvt. Ltd., an independent team based in Bengaluru, India. Company details: Legal name: Tiles Privacy Technologies Pvt. Ltd. GSTIN: 29AANCT5152A1ZB PAN: AANCT5152A CIN: U58200KA2026PTC226312 TAN: BLRT28790G Contact: Press and general inquiries: hello@tiles.run Phone: +91 7338014129 Address: WeWork Prestige Atlanta, 80 Feet Rd, Koramangala, Bengaluru, IN 560034 Brand assets: https://tiles.run/tiles-brand-assets.zip Brand guidelines: https://tiles.run/brand Background talk: https://youtu.be/WY_M7TMQ8do Adapted blog post: https://tiles.run/blog/own-your-ai Product screenshots: Tiles App, Menu bar app, shared conversation, and Tiles CLI. ================================================================================ ## About (https://tiles.run/about) About Tiles Privacy. Our mission is to build software that gives people greater agency, control, and choice in their digital lives. We believe that privacy adoption at scale must work backwards from preserving utility. This means negligible impact on user experience, model intelligence, throughput, latency, tool use & agentic capabilities, and web access. We’re proud to be one of three anchor projects in the Mozilla Foundation’s new Human-Scale AI incubator cohort, backed by $300,000 in non-dilutive funding to help advance our mission. Human-Scale AI incubator cohort: https://www.mozillafoundation.org/en/what-we-do/grantmaking/incubator/human-scale-ai/ Tiles was born from the discussions in User & Agents (https://www.userandagents.org), a community focused on shaping the future of user-agent systems. We are also a signatory to the European Social Stack initiative (https://european.social/#signatories), supporting an open, interoperable, and publicly accountable digital ecosystem for Europe. Tiles Privacy is built by a small independent team of three: Ankesh Bharti, Anandu Pavanan, and Prashant Mishra. The project is advised by Boris Mann, Dietrich Ayala, and Gordon Brander. ================================================================================ ## Sponsor (https://tiles.run/sponsor) Sponsor Tiles Privacy. Support a small team building private, local-first AI that preserves user agency. We are grateful to the individuals and organizations who support our work financially, including through GitHub Sponsors and cryptocurrency donations. Current sponsor: Jeremie Miller @jeremie.com (https://bsky.app/profile/jeremie.com). Current sponsor: Boris Mann @bmann.ca (https://bmannconsulting.com/). Current sponsor: Luke Hubbard @lukeinth (https://bsky.app/profile/lukeinth.bsky.social). Current sponsor: Dietrich Ayala @autonome (https://metafluff.com/). Current sponsor: Ethan Frey @ethanfrey (https://github.com/ethanfrey). Current sponsor: Hugo Duprez @HugoDuprez (https://www.hugoduprez.com/). Current sponsor: Utkarsh Saxena @saxenauts (https://saxenauts.io/). Current sponsor: Dev Doshi @devdoshi (https://github.com/devdoshi). GitHub Sponsors: https://github.com/sponsors/tilesprivacy Current recurring sponsorship: $1,320/month. ================================================================================ ## Tiles at India FOSS (https://tiles.run/tiles-at-india-foss) Tiles at India FOSS Speaker: Ankesh Bharti Presented at IndiaFOSS 2026 in Bengaluru. Slides and speaker-note transcript: This post is adapted from Ankesh Bharti’s IndiaFOSS 2026 talk in Bengaluru. It is written for anyone thinking about how AI should fit into our digital lives. As AI becomes central to how we work and communicate, I believe we are seeing a new form of technological feudalism, where a handful of platforms control the models, identities, data, and distribution channels people depend on. Local-first AI offers an alternative, but many tools still lack the identity, sync, and collaboration features people expect. Thank you, Akshit, for the introduction, and thank you to the FOSS United team for organizing this event. Hi everyone, I’m Ankesh, founder & CEO of Tiles Privacy. Today I want to talk about what it means to actually own your AI. Not just the model, but the data, identity, and infrastructure around it. And I think two things make that possible now: recent developments in open models and adoption of decentralized protocols. I’m also a co-founder and steward of User & Agents, a community shaping user-agent systems that give people more agency, control, and choice, and Tiles was born out of those discussions. I like to call myself a technologist and am currently based in Pune. My ambition is to build a decentralized stack that expands user agency in our digital spaces. The thesis of this talk is pretty simple. AI is becoming part of how we think, work, research and communicate. And as that happens, whoever controls the AI layer starts controlling a surprisingly large part of our digital lives. I think we now have the technology to build that relationship differently: run intelligence locally, and use open protocols where we need a network. Most of us in this room probably use several of these AI agents already. And they’re becoming much more than chatbots. They read our code, browse the web, operate tools, work with our files, handle everyday tasks, and increasingly act on our behalf. So naturally, we’re giving them more and more context about ourselves. And I actually like ChatGPT. What keeps me using it isn’t just the model. It’s the product around the model, the consistency, the memory, and being able to pick up the same context across different surfaces. It starts to feel less like using a chatbot and more like using software that actually knows you. But the better that gets, the more one-sided the relationship becomes. The system knows more and more about me, but all of that context ultimately lives inside an account and infrastructure I don’t control. If I leave the platform, a growing part of that accumulated digital memory stays behind. I like the relationship. I just don’t like the dependency. My conclusion wasn’t that I should stop using AI. I needed healthier boundaries. I want to keep the same convenience without depending on blind trust. I want my identity and context to stay with me across every app I use, with trust that I can verify computationally. I still want the relationship. I just want it to be on my terms. So this became my preference: private and local. And the good news is, today’s local AI tools are already technically excellent. They’re naturally great at private, personal use. Frontier AI is no longer locked behind proprietary APIs. For many practical workloads, frontier-level capabilities are already available in open-weight models such as GLM series, as shown in this chart by Artificial Analysis. The amount of compute we now have in consumer devices makes it possible to run even frontier models locally. Technologies like UltraFusion combine two Apple Silicon Max chips into a single Ultra chip, enabling medium-class local models to run on device. We’re also finding smarter ways to run larger models at the edge. Apple’s upcoming Siri in iOS 27 is powered by Foundation Model 3, a distilled version of Gemini, and runs a 20B Mixture-of-Experts model directly on the iPhone. It loads expert weights from fast flash storage instead of keeping the entire model in memory, and by loading them once per prompt rather than once per token, it largely compensates for the higher latency of flash storage. But local inference alone does not give us a complete product. As soon as we want identity, multiple devices, sync, or collaboration, we often recreate exactly the architecture we were trying to escape. So the model may be local while the product relationship becomes centralized again. What if we put the user, and their keys, at the center, and built outward? The keys belong to the user on their own devices, not the provider. They establish their identity and what they control. Then come their devices, models, and everything else. The point is that user ownership shouldn’t stop at the model layer. As an AI disclosure, our main branch contains manually reviewed code, with core systems largely handwritten. Our canary branch is where we experiment more aggressively with AI-generated code, primarily for client-side features and UI/UX work above the API layer. This helps us prototype quickly, test ideas with users and the team, and learn what actually works. Features that prove useful are gradually brought into main through smaller, carefully reviewed small PRs rather than merging experimental code wholesale. That’s what we’re building with Tiles. Tiles is a local-first, collaborative AI assistant. And local-first means something very specific: the product should keep working, even if we stop working on it. Your data, identity, and core experience don’t depend on Tiles continuing to exist as a company or service. The goal is to give people a familiar AI experience, while changing the architecture underneath so the user remains at the center of control. It’s software built to outlive us. Before we go any further, I’d like to give you a brief live demo of what’s available in our canary release today. This is the deeper technical view of Tiles, broken into a few separate modules. The core is written in Rust. It includes local storage, the Modelfile parser, the plugin system, peer-to-peer networking, social layer with AT Protocol, and our PKI and identity system built for zero trust authentication and authorization. Inference is a separate Python module, with llama.cpp serving local models behind an Open Responses API translation layer. Then there’s the agent runtime. Its control plane is written in Rust, with the TypeScript agentic loop powered by Pi, embedded as a Bun binary. And finally, different interfaces, like the macOS menubar app and desktop app, sit on top which uses Tilekit APIs. I’m not going to walk through every box here. The main idea is that Tiles is modular by design, so identity, networking, inference, agents, and interfaces can evolve independently without everything being tied into one monolithic application. Now that you have a brief overview of the product and its technical architecture, I’d like to walk you through the three novel ideas that set us apart. First, user-owned keys with Tiles Account. DID, Decentralized Identifiers, gives us the identity primitive. UCAN, User Controlled Authorization Network, gives us the authorization primitive. Together, these make your Tiles Account, generated and secured locally on your device keychain, rather than being an account created and controlled on a centralized Tiles server. The easiest way to understand a DID is: DID is who you are. It’s a portable identifier controlled by your keys. Services can verify you, but the service itself doesn’t have to be the source of your identity. And if DID answers: Who are you? UCAN answers: What are you allowed to do? In Tiles, UCAN provides scoped authorization for syncing chats across devices, among other uses. UCAN uses capability-based authorization, rather than the access control lists, or ACLs, commonly used in centralized systems. Instead of a central server checking a list of permissions, you present a signed capability granting specific authority, potentially with an expiry. So instead of giving another device a permanent password, I can grant exactly the authority it needs. That’s a much cleaner fit for local-first and peer-to-peer systems. Second is local-first AI with Tiles Network, which works across local, online, and discovery layers. You get local devices, ambient compute, private peer-to-peer networking, and an open social layer, without requiring a central Tiles server to sit in the middle. The basic rule is simple: keep ownership close to the user, and introduce the network only where the network adds value. You have the devices you actually use, your phone, laptop, and what I’d call ambient AI compute. That could be a homelab, a workstation in the office, or any computer you control that can sit in the background and provide AI inference when you need it. These devices can talk directly over your local network, so this can work without the internet at all. To connect across networks, Tiles uses end-to-end encrypted peer-to-peer networking with public relays built with Iroh. And for collaborative features, we use AT Protocol and the user’s own Personal Data Server. The analogy here is the open web. Your website works across different browsers because the browser doesn’t own the underlying web. AT Protocol brings a similar idea to the social layer. Your data lives in your own repository, which you can think of a bit like a GitHub repository for your digital life. Different applications can read from and write to that same repository, rather than each app keeping your identity and data trapped in its own database. So your identity and content can work across multiple applications, and changing applications doesn’t mean starting your digital life all over again. Third is our opinionated AI stack, with Gemma 4 as the current default series. We handle model-specific tuning across llama.cpp, the Pi harness, and quantization, so you don’t have to configure everything yourself. For extensibility, we support the Agent Plugins standard, allowing compatible plugins from clients like Cursor or ChatGPT to work in Tiles. Install them through our curated marketplace or directly by specifying a path. With Tilekit REST API endpoints, developers just want the underlying runtime and capabilities inside their own applications. Tilekit is our way of making Tiles embeddable, so developers can build their own interfaces and products on top of the same underlying infrastructure. Tiles can be the application, or it can simply provide the building blocks. Before I wrap up, there’s one more thing I’d like to share. We’re announcing a major partnership with the Mozilla Foundation soon and are looking for organizations to help pilot and test what we’re building. Over the past year, we’ve grown into a team of five. Starting next month, when our partnership with Mozilla begins, we all will be working on Tiles full time. I’m grateful to Boris Mann, Dietrich Ayala, and Gordon Brander for their advice and guidance, drawing on their experience in decentralized systems, browsers, and the open web. Tiles is really a product of the open source community, a student-run open-source club which i am also a part of User & Agents has been an incredible community partner where many of these ideas took shape. Darkshapes, our design partner, designed the Tiles logo and helped turn our ideas into the foundational visual identity of Tiles. Special thanks to Solstone and its founder, Jeremie Miller, for being a close partner and sponsor of Tiles. Thank you to Dietrich and Luke, my co-founders at User & Agents. To Boris, Xi Zhang, Hugo, and everyone who sponsored Tiles, shared advice, or helped along the way: I wouldn’t be standing here today without you. If you’re interested in sponsoring Tiles, providing funding, or exploring collaboration opportunities, please come talk to me afterwards. To recap: I love ChatGPT, but I don’t want to compromise on convenience or control. Local AI and open protocols let us keep the convenience while making our data, identity, and memory portable and truly ours. I’d love for you to try Tiles on Mac or Linux and tell me what you think. If you’d like to contribute or chat about local-first AI, please join our new Discord server through this QR or mail me at this address. Thank you. ================================================================================ ## Blog Index (https://tiles.run/blog) The Tiles Blog Privacy technology for everyone. Posts here use the Standard.site lexicon for rich presentation in supported ATproto clients and are stored on a PDS hosted by Eurosky. Published posts: 6 ================================================================================ ## Blog Post: Tiles Privacy joins Mozilla Foundation’s Human-Scale AI Incubator as an anchor project (https://tiles.run/blog/tiles-joins-mozilla-ai-incubator) Published: 2026-10-21 Author: Ankesh Bharti @feynon Author URL: https://ankeshbharti.com Description: With support from Mozilla Foundation’s Human-Scale AI Incubator, we will spend the next 18 months building private, user-owned AI for the public interest. Content: Today, Tiles is joining Mozilla Foundation’s Human-Scale AI Incubator as one of three anchor projects. The Incubator brings together teams building purpose-built technology, sized to the problems they are meant to solve. Privacy has historically been a niche market. I believe AI will change that. AI assistants and agent swarms are becoming the interface for more of our daily work, from knowledge work and coding to browsing. As that happens, attacks and data leaks will affect more people. Tiles is our bet that people will want tools that keep their data, identity, and control in their own hands. For us, the hard part is building the underlying privacy technology and a sustainable business, not another chat interface. ChatGPT has already set a strong standard for how AI assistants look and feel. We can learn from those patterns while making Tiles distinctly ours: more playful, more human, and guided by the belief that work can feel like play. We want to build humane software, using polish to serve the user rather than drive addiction or endless engagement. Underneath, we are integrating local models and agent harnesses, building peer-to-peer networking, and creating zero-trust identity and authorization for people and agents. The goal is a decentralized, user-owned stack built to last, without ads or incentives that work against users. That is why becoming an anchor project matters so much: it gives us time. Mozilla’s support provides us with 18 months of runway for four full-time team members, one student on a short-term placement, and one legal consultant. Our core team brings together engineers with experience in cybersecurity, gaming, and peer-to-peer technologies, and a designer with a background in direct-to-consumer brands. Our legal consultant specializes in technology law and will work on the governance, risk, and compliance aspects of Tiles deployments with our pilot partners. This support gives us the freedom to build the local AI product we believe in without giving up equity or control. Members of the Tiles Privacy team. During that time, we’ll work closely with Mozilla Foundation and the broader Human-Scale AI cohort through regular discussions, coaching, feedback, and community engagement. We also plan to run practical pilots with nonprofits and educational institutions serving charitable and public-interest goals. Working in real settings will show us what people need and help us set better product priorities. The pilots will let us deploy carefully, learn from students, educators, program leaders, and communities, and make thoughtful decisions without the pressure of a sales cycle. These pilots will also shape a governance and safeguarding framework for responsible institutional use. We will release it under an open-source license so nonprofits, schools, universities, and other organizations can adapt it for their own communities. For me, long-term success is straightforward: Tiles becomes self-sustaining through user and enterprise revenue, giving us the independence to keep building. Seven more spots are open now with up to $500k over two years in non-dilutive funding. Applications close November 20, 2026. If you’re building AI for a language, place, or need that mainstream systems overlook, we’d love to have you with us. Learn more and apply through the Human-Scale AI Incubator. We’re grateful for Mozilla Foundation’s support and excited about what it will help us build next. We also want to thank our sponsors, advisors, and every member of the User & Agents community who played a vital role in helping Tiles reach this milestone. ================================================================================ ## Blog Post: Atmopsheric sessions (https://tiles.run/blog/atmospheric-sessions) Published: 2026-07-24 Author: Anandu Pavanan @madcla.ws Author URL: https://bsky.app/profile/madcla.ws Description: Share Tiles chat sessions publicly or privately while retaining ownership with AT Protocol Content: In Tiles, the chat sessions we have with local models can be shared publicly. This is similar to sharing conversations as Shared Links in ChatGPT or via Pi (using GitHub Gists). Sharing our research, ideas, and musings with others is valuable. What Tiles explores is how much ownership we can retain over those shared conversations. A publicly shared Tiles chat link In Tiles, all chat sessions are completely local and stored encrypted on your device. So when we want to share those local conversations with the outside world, we should preserve the same ethos. There are two ways to share sessions in Tiles. The first is to sync chats end to end encrypted, peer to peer, across your own devices, as described here. That approach provides the strongest privacy and the most granular control, and deserves its own blog post. But what if you simply want to share your research, ideas, or musings as a regular web link that anyone can open, even if they don't have Tiles installed, similar to ChatGPT's Shared Links, while still preserving data ownership? And what if other applications could build on those publicly shared conversations for entirely new use cases? This is where AT Protocol comes into the picture. Reaching for the Atmosphere AT Protocol, also abbreviated as ATproto, is a decentralized social networking protocol that lets users publish and distribute self-authenticated data. That one-line description doesn't do it justice, so we highly recommend Dan Abramov's excellent explanation of it here. For our use case of sharing chat sessions, ATproto provides two important guarantees: a permanent identity and the ability to move your data anywhere without breaking existing shared links. Even if Tiles were to stop existing, your shared sessions would remain accessible, and anyone could build another application to display them. The data, its format, and the protocol are all open, much like Markdown. Tiles doesn't own your shared sessions. They live in your PDS (Personal Data Server in the ATproto ecosystem), and you're free to move to another PDS whenever you want. When you share a session from Tiles using ATproto, the data is published to your PDS, not stored on Tiles' infrastructure. You can host your own PDS or choose one operated by someone you trust. This separation of applications from identity and data is one of ATproto's core ideas. If you stop using one microblogging app and switch to another that also speaks ATproto, you don't lose your identity, your followers, or your posts. Your identity, social graph, and data move with you across applications, forming what the ATproto community calls the Atmosphere. Sharing sessions with Tiles To share a session from Tiles, you first need an ATproto account. The easiest way to get started is by creating a Bluesky account. Every ATproto account is associated with a PDS (Personal Data Server), which is where your data is hosted. For example, you can create a Bluesky account and use Bluesky's PDS. There are, of course, other PDS providers as well, such as Northsky and Eurosky. The important point is that you can move your account to a different PDS later if you choose. For example, you can migrate from Bluesky's PDS to Northsky's without changing your ATproto handle or your underlying identity, both of which remain the same. Once you have an ATproto account, you can sign in to it from Tiles using your ATproto handle, as described here. After that, you can open the Tiles CLI (with a web UI coming soon) and share either the current conversation or any existing session using the /share command. Tiles publishes the session to your ATproto PDS and returns a public link that anyone can access. For more details, see the documentation. Your browser does not support embedded video. Download the video . What about private sessions? Sometimes we want to share a session only with specific people rather than making it public to everyone. One limitation of ATproto today is that records stored in a PDS are public by design, enabling data portability, transparency, and interoperability. There is ongoing work to support permissioned data, but that is not available yet. To preserve the privacy of sensitive Tiles sessions, Tiles supports private sharing by encrypting the session locally before it is uploaded to the PDS. The encrypted data is stored in your PDS, while the encryption key is placed in the URL fragment (#...). Since URL fragments are never sent to the server, decryption happens entirely in the recipient's browser. This means your PDS stores only encrypted data, and only someone with the complete link can decrypt and view the session. Encrypted sessions in Atproto PDS Here's an example of a private shared session. If you inspect the URL, you'll notice that the encoded encryption key (TmqE5ZwyWaCl/6wCI5R0AsCWwlg2GZ5D.vyLaXFpy6dnB6G9jbHr8aOIxg5hBNeA+KB0v0DQrUkE=) is included as a URL fragment after the #. You can also verify that the corresponding data stored in the PDS is encrypted by inspecting it here. Because the encryption key never becomes part of the data stored in the PDS, the session remains encrypted while publicly hosted. Only someone with the complete URL can decrypt and view it, since decryption happens entirely in the browser. Under the hood, Tiles uses ChaCha20-Poly1305 for authenticated encryption. Interoperable sessions We mentioned earlier that sessions shared through Tiles can outlive Tiles itself. One reason is that the underlying data lives in a user-controlled PDS. But that alone isn't enough. If the data is stored in a proprietary format that requires reverse engineering to use outside of Tiles, then the only thing you've gained is the ability to export a data dump. Credible exit requires more than that. As mentioned earlier, ATproto already makes it possible to move from one social application to another without losing your identity, social graph, or data. The same principle should apply to AI conversations. It's similar to how a Markdown file can be edited in Notepad and then opened in VS Code without any conversion. It would be even more powerful if we had that level of interoperability for everything, from social posts to LLM chat sessions. In fact, this already exists for posts on ATproto. I can create a post in Mu, then open and edit that same post in Bluesky while using the same ATproto account, the same identity, and the same underlying data storage. If I ever decide I no longer like Bluesky's interface, or simply prefer another client, I can switch to Mu without worrying about losing my followers or my content. Creating a post on Mu Viewing the same post on Bluesky It would be exciting to bring that same interoperability to LLM chat sessions. Imagine publishing a local conversation from Tiles and opening it in a different chat viewer. Or imagine publishing a conversation created in ChatGPT, importing it into Tiles, continuing the conversation locally, publishing the updated session, and then opening it again in another compatible application. Just like a text file, the conversation would no longer be tied to a single app. ATproto enables this kind of interoperability through Lexicons. A Lexicon is essentially a JSON schema, with a few ATproto-specific extensions, that defines the structure of a particular type of data so it can be understood consistently across the network. As a first step toward interoperable AI conversations, Tiles defines a Lexicon for LLM chat sessions called run.tiles.chat.sessionSnapshot. { "id": "run.tiles.chat.sessionSnapshot", "$type": "com.atproto.lexicon.schema", "lexicon": 1, "defs": { "main": { "key": "tid", "type": "record", "record": { "required": ["name", "sessionId", "createdAt", "turns"], "properties": { "name": { "type": "string" }, "sessionId": { "type": "string" }, "createdAt": { "type": "string", "format": "datetime" }, "turns": { "type": "array", "items": { "type": "object", "properties": { "model": { "type": "string" }, "messages": { "type": "array", "items": { "ref": "#message" } } } } } } } }, "message": { "type": "object", "required": ["role", "content"] }, "contentItem": { "type": "object", "required": ["type"] } } } All sessions published through Tiles use this Lexicon. In that sense, the Tiles session viewer acts as a free viewer for any session published in this format. You don't even need Tiles to create the data. Any application can publish a session directly to a user's PDS using the ATproto APIs, and the Tiles viewer can render it. This opens up some interesting possibilities. Under the hood, Tiles uses Pi as its agent harness, and Pi is also used by several other assistants, including OpenClaw. Imagine if there were a standard Lexicon for Pi sessions. The level of interoperability would be remarkable. Conversations could move seamlessly between applications built on the same underlying session format. For example, if you tagged a friend in a Tiles chat session, that mention wouldn't be lost when the conversation was opened in another ATproto-compatible AI assistant application. The conversation, its metadata, and its social context could all travel together. We'll continue experimenting with ATproto as we build more features in Tiles. ATproto aligns closely with the principles we care about: collaboration, credible exit, and user agency. We believe conversations should be portable, interoperable, and ultimately owned by the people who create them. That's the future we're building toward, so you can truly own your sessions. ================================================================================ ## Blog Post: Own your AI with local models and open protocols (https://tiles.run/blog/own-your-ai) Published: 2026-07-14 Author: Ankesh Bharti @feynon Author URL: https://ankeshbharti.com Description: A Local-First Conf talk about local models, open protocols, and user-owned AI Content: This post is adapted from a talk I gave at Local-First Conf in Berlin in July 2026. It was written for the local-first community, but it is relevant to anyone involved in building software. As AI becomes central to how we work and communicate, I believe we are seeing a new form of technological feudalism, where a handful of platforms control the models, identities, data, and distribution channels people depend on. Local-first AI offers an alternative, but many tools still lack the identity, sync, and collaboration features people expect. Local-First Conference Video Watch the talk on YouTube Slides and Transcript Slide 1 Thank you, Adam, for the introduction, and thank you to the Local-First Conference team for organizing this event. Hi everyone, I’m Ankesh. Usually I go by feynon on the internet. I was here in the audience last year, and it genuinely changed the direction of my work, so it’s an honor to be back as a speaker. Slide 2 Today, I want to talk about reclaiming control of our digital lives in the age of AI. I think that starts by running AI locally, on our own devices. And it continues by building on open protocols instead of closed platforms. Together, those two ideas let us own our data, our identity, and how our AI works. Slide 3 I love ChatGPT, and I’ve been using its products since they launched. What keeps me coming back isn't just the models. It's the consistency of the user experience and the continuity that memory provides across its product surfaces. It feels less like using a chatbot and more like using an app that knows me. It started feeling more like a relationship. And that made me ask a different question: what kind of relationship do I actually have with these systems? Slide 4 That's when I realized the relationship had become one-sided. The more ChatGPT learned about me, the more power it held over my digital life. If I stop paying the rent, part of my digital memory disappears with it. And because I don’t fully trust who can access what I share, I can’t always express myself freely. I love using AI. I just don't love depending on something I don't own or control. Slide 5 I needed healthier boundaries. I want to keep the same convenience without depending on blind trust. I want my identity and memory to stay with me across every app I use, with trust that I can verify computationally. I still want the relationship. I just want it to be on my terms. Slide 6 That naturally led me to one question. Can we actually build AI like this today? I think we finally can, with the technology we have available today. Three things have changed. Slide 7 First, the frontier AI is no longer locked behind proprietary APIs. For many practical workloads, frontier-level capabilities are already available in open-weight models such as GLM 5.2, as shown in this chart by Artificial Analysis. Slide 8 The second change is the amount of compute we now have in consumer devices. Technologies like UltraFusion combine two Apple Silicon Max chips into a single Ultra chip, enabling medium-class local models to run on device. Slide 9 It’s not just about running frontier models on expensive on-device setups. As frontier open-weight models improve, techniques like distillation rapidly transfer those gains to smaller local models. Small models are delivering significantly more intelligence per watt. Slide 10 We’re also finding smarter ways to run larger models at the edge. Apple’s upcoming Siri in iOS 27 is powered by Foundation Model 3, a distilled version of Gemini, and runs a 20B Mixture-of-Experts model directly on the iPhone. It loads expert weights from fast flash storage instead of keeping the entire model in memory, and by loading them once per prompt rather than once per token, it largely compensates for the higher latency of flash storage. Slide 11 The third change is the growing adoption of open protocols like ATproto and ActivityPub among others. Bluesky, built on ATproto, has grown to over 45 million users, with a thriving developer ecosystem building user-owned applications. Slide 12 We now have the models. We now have the compute. And we now have the protocols. The technology is finally here. But products haven’t caught up yet. Slide 13 Today’s local AI tools are technically excellent. They’re built around private, personal use, and local AI is naturally great for that. But privacy doesn’t mean I don’t want to collaborate. I still want to share, work together, and move between my own devices, just on my own terms. Most local AI products simply don’t support that. Slide 14 And when they do, they still depend on platforms. Collaboration features usually require a centralized login, like “Sign in with Google.” So instead of owning my identity, I’m still relying on someone else’s platform. I just traded one platform dependency for another, even with supposedly private local AI tools. Slide 15 So I started thinking about what my dream local AI tool would look like. Everything on this slide comes down to one idea. I wanted all the polish of modern AI products, but working for me instead of the platform. And that means polished on-device models, peer-to-peer sync, user-owned identity, shared links, and developer tools that make local AI feel just as seamless as the cloud. Slide 16 And it's not just my dream, it's a shared one. This post, shared earlier today by Eileen, describes a similar vision of an open, local setup. Slide 17 That led me to build Tiles, a local-first private AI assistant. Today it’s in alpha with a CLI-only experience. Tiles is built to make ownership the default, without compromising on convenience. Slide 18 The architecture follows one simple principle. Keep ownership on the device. Use the network only where it adds value. The app, models, and your data live on your local devices. The cloud is only used for collaboration. The ATproto PDS powers social features, while end-to-end encrypted peer-to-peer sync is done with Iroh relays. Slide 19 The technical architecture is split across three layers: Rust handles the core systems, Python powers inference, and TypeScript runs the agent runtime, which embeds Pi as a Bun binary. If you’d like to explore any particular module, I’d be happy to discuss it in more detail after the talk. Next, here’s what that looks like across Tiles’ various features. Slide 20 Tiles includes gpt-oss-20b by default. It uses the Modelfile format, a plain-text blueprint for building and customizing local AI models. Slide 21 Plugins let users extend Tiles with reusable workflows by installing SKILL.md files. Slide 22 Tiles securely connects to local models running on remote machines over a peer-to-peer network, giving you access to your ambient AI compute wherever you are. Slide 23 That same peer-to-peer foundation enables encrypted chat synchronization across linked devices, using locally generated DIDs and UCANs for zero-trust identity and authorization. Slide 24 Finally, chat sessions can be shared through public or private links and published as ATproto Lexicon records. Slide 25 Now, with that overview, let’s move on to a demo I recorded yesterday after being delighted by Tristan’s demo of Caldir CLI. Slide 26 This recorded demo shows Caldir running as a Tiles plugin with remote inference. I’ll ask it to find events, then create an event. Finally, I’ll share the chat and show the saved ATProto PDS record as a Tiles lexicon. What impressed me is that this speed was possible locally because of caldir’s simple, plaintext-first design, combined with the vertical integration we’ve built into Tiles across the inference stack. Slide 27 The three of us have been working full-time on maintaining Tiles for the past six months. Slide 28 I’m grateful for the guidance of Boris Mann, Dietrich Ayala, and Gordon Brander on this project. Slide 29 Tiles is really a product of the local-first community, and many of the technologies we use in Tiles came directly from the work of people in this room. User & Agents has been an incredible community partner where many of these ideas took shape. Darkshapes, our design partner, designed the Tiles logo and helped turn our ideas into the visual identity of Tiles. Slide 30 Special thanks to Dietrich and Luke, my co-founders at User & Agents. Thank you to Boris, Xi Zhang, Hugo, and everyone who sponsored Tiles, shared advice, or helped along the way. I genuinely wouldn’t be standing here today without you. If you’re interested in sponsoring Tiles, providing funding, or exploring collaboration opportunities, please come talk to me afterwards. Slide 31 To recap: I love ChatGPT, but I don’t want to compromise on convenience or control. Local AI and open protocols let us keep the convenience while making our data, identity, and memory portable—and truly ours. I’d love for you to try Tiles on Mac or Linux and tell me what you think. If you’d like to contribute or chat about local-first AI, please come find me afterwards. Thank you. ================================================================================ ## Blog Post: Controlling the Ctrl-C (https://tiles.run/blog/controlling-ctrl-c) Published: 2026-06-08 Author: Anandu Pavanan @madcla.ws Author URL: https://bsky.app/profile/madcla.ws Description: Observations while trying to properly exit from Tiles CLI Content: The REPL UI issue As a local AI assistant, Tiles embeds Pi agent for agent harness. Since the REPL is written in Rust and Pi is in TypeScript, we embed the Pi Bun binary and use it via Pi's RPC mode, spawn a headless Pi binary as a child process, and communicate with it via standard streams (stdin/stdout/stderr) in JSON format. The user input to the model and the streamed output from the model come and go through Pi. It sits between the REPL and the inference system. As with any LLM inference interface, Tiles REPL must stop the output streaming from the model as soon as the user presses Ctrl-C and the REPL should return to prompt state, ideally like this. But in the versions before v0.4.11, although the streaming ends and REPL returns to prompt state, on the next user input we were greeted with a broken pipe error like Err value: Os { code: 32, kind: BrokenPipe, message: "Broken pipe" }. Because of this, users had to restart the REPL to continue. More details are in this issue. The broken pipes As mentioned, we spawn the Pi process as a child process and communicate through its stdin and stdout. For this reason the streams are connected via pipes rather than the child inheriting the parent's streams (which is the default behavior). If the child inherited the parent's streams, communication would be messy and processes would have to filter what they need from the shared stream, which would introduce race conditions. When piped, the parent can write to the child's stdin; the child writes to its own stdout, which the parent can then read, giving a clear separation of concerns. This is how we explicitly set the streams to be piped in Rust. let pi_process = Command::new(pi_exec_path) .arg("--mode") .arg("rpc") // default is Stdio::inherit .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() .expect("failed to run Pi"); So when we press Ctrl-C, the SIGINT (signal interrupt) event is propagated to the child processes, and if they don't handle it then the default behavior is to exit. To monitor this, we can use the following commands on Unix systems. ps -o pid,ppid,pgid,sid,command | grep tiles 88068 65985 88608 target/debug/tiles Here the processId is 7011, the parent's processId is 65985 (system root is parent), and the process's groupId is 7011. To inspect the children, we can use: // where 88068 is pid for tiles pstree -p 88068 \-+= 88068 tiles target/debug/tiles |--= 88098 tiles target/debug/tiles daemon \--= 88099 tiles /Users/tiles/tiles/.tiles_dev/tiles/pi/pi --mode rpc We can see the Pi process is running as a child of Tiles with PID 88099. We can use lsof to further monitor their relationship as follows: ➜ lsof -p 88099 // Pi's PID (child) COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME pi 88099 tiles 0 PIPE 0xd5c96c81e3aec5c2 16384 ->0xa95f7f46dfb5efe6 pi 88099 tiles 1 PIPE 0x745d3d0e7a7709aa 16384 ->0x27aceab27161a82 ➜ lsof -p 88429 // Tile's PID (parent) COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME tiles 88068 tiles 16 PIPE 0xa95f7f46dfb5efe6 16384 ->0xd5c96c81e3aec5c2 tiles 88068 tiles 17 PIPE 0x27aceab27161a82 16384 ->0x745d3d0e7a7709aa Here we can see Pi's stdin (FD=0) is connected to Tiles stdout (FD=16) and vice versa. So when we press Ctrl-C to stop a streaming response, the signal propagates to the Pi process and Pi exits. When we try a new user prompt next time in the REPL, unbeknownst to the REPL that such a process does not exist, it still tries to write to Pi's non-existent stdin, which gives us a broken pipe, aka a broken connection. Letting them go Since by default a child process is in the same process group (pgid) as the parent, the SIGINT event is propagated to all the processes in the group. One way is to remove the child from the same group as the parent. This means they still have a parent-child relationship, but the parent is no longer in direct control of the children. On Unix we can use setsid for this to create a new session and set the current process as the leader of it. But to do that in Rust is an unsafe operation (where we lose safety assurance from the compiler), as setsid is only available in the nightly version as of now, so we need to call it via C FFI. So setsid is achieved via other libraries such as libc, nix, etc., of course colored by the unsafe keyword. let pi_process = unsafe { Command::new(pi_exec_path) .arg("--mode") .arg("rpc") .stdin(Stdio::piped()) .stdout(Stdio::piped()) // runs the below closure before executing the // command function, here we run setsid for the // spawned process. .pre_exec(|| { if libc::setsid() == -1 { return Err(std::io::Error::last_os_error()); } Ok(()) }) .spawn() .expect("failed to run Pi") }; This resolves our broken pipe issue, as the SIGINT is never reaching the Pi process. But now we have another issue on hand: the model streaming is non-stoppable via Ctrl-C, and the REPL is completely unresponsive during the entire time we are streaming the output from Pi's stdout. It's no longer respecting SIGINT. Controlling the Control-C Thanks to a serendipitous moment while surfing the rustyline repo, which we use for building a nice UX for our REPL, we found that the version we were using (v17) had a bug which masks the SIGINT event. So we upgraded to the latest version, and now we are receiving SIGINT while the model is streaming, but the SIGINT exits the program altogether instead of stopping the stream and returning to the user prompt. This is in fact expected, as normally programs should handle SIGINT themselves if they want to do cleanups, graceful shutdowns, etc. So we use the ctrlc library to handle SIGINT, which uses a dedicated thread for handling the event. let is_running = Arc::new(AtomicBool::new(true)); let is_running_ref = is_running.clone(); ctrlc::set_handler(move || { is_running_ref.store(false, std::sync::atomic::Ordering::SeqCst); }) .... .... while is_running.load(std::sync::atomic::Ordering::SeqCst) { // loop breaks when SIGINT is fired and above handler toggles // is_running to false } But again, for some reason we are back to square one where the REPL is non-responsive to Ctrl-C when it's streaming the output. As in the above signal handler is not getting called on SIGINT. Turns out the way we read from Pi's stdout is a synchronous, blocking operation. So we tried converting all the functions related to this to async using the corresponding async functions provided by tokio (an async runtime library for Rust). For example, the core operation here is using a buffered reader to read from Pi's stdout efficiently, so we replace the BufReader from the std library with the async BufReader provided by the Tokio runtime. > Tokio uses co-operative scheduling to switch between its tasks, so when we use an async function, it will yield frequently instead of blocking throughout the process. Once we refactored the codebase to be async, we started getting SIGINT events in the handler we set using the ctrlc library before, and the program no longer exits either. Now all we have to do is abort the Pi session by sending an abort event to Pi and do the cleanup from our side. while let Some(line) = reader.next_line().await? { if !is_running.load(std::sync::atomic::Ordering::SeqCst) { info!("Ctrlc detected, aborting Pi ops"); let end_payload = json!({ "type": "abort", }); // sending abort event to Pi send_to_pi(pi_stdin, end_payload).await?; // toggling is_running back to true, once we handled // the ctrl-c is_running.store(true, std::sync::atomic::Ordering::SeqCst); continue; } For more details on the sync-async conversion, see the PR diff. Unexpected entry of SIGPIPE The interesting thing now is that when we exit the main REPL program, the Pi process also exits, which shouldn't be the case as both are now in different process groups, right? Could this be related to the pipes getting closed on one end? Although this is fine for us, as we don't want the Pi process to be a background daemon and go rogue, it's important to understand what's happening under the hood, as we also have a Tiles daemon process (which is a background headless Tiles HTTP server) that is still alive even after the main REPL program closes, as it is supposed to be (this was also spawned in a different process group). // where 88068 is pid for tiles pstree -p 88068 \-+= 88068 tiles target/debug/tiles |--= 88098 tiles target/debug/tiles daemon \--= 88099 tiles /Users/tiles/tiles/.tiles_dev/tiles/pi/pi --mode rpc PID=88098 is our daemon. Why the dual behavior for the same action? For that we can live-debug the Pi program using lldb (LLVM debugger) to see what happens when the parent exit. We will attach the Pi process to lldb, add a breakpoint for SIGPIPE, then step through to see if Pi is handling SIGPIPE or not. The actions we did are commented with numbered index. // (1) Starting lldb for the Pi process ➜ sudo lldb -p 88099 No entry for terminal type "xterm-ghostty"; using dumb terminal settings. // (2) Attaching Pi PID to the debugger (lldb) process attach --pid 88099 Process 88099 stopped Target 0: (pi) stopped. Executable binary set to "/Users/tiles/tiles/.tiles_dev/tiles/pi/pi". Architecture set to: arm64-apple-macosx-. No entry for terminal type "xterm-ghostty"; using dumb terminal settings. // (3) Adding a breakpoint for SIGPIPE and notify us (lldb) break set -n write Breakpoint 1: 19 locations. (lldb) process handle SIGPIPE --pass false --stop true --notify true NAME PASS STOP NOTIFY =========== ===== ===== ====== SIGPIPE false true true // (4) Resuming the debugger (lldb) process continue // At this point we exit the Tiles repl and debugger pauses // Pi Process 88099 resuming Process 88099 stopped // (5) and continue the Pi program after resuming after the breakpoint (lldb) process continue // We can see that Pi program exits as soon as it // receives SIGPIPE Process 88099 resuming Process 88099 exited with status = 0 (0x00000000) As seen in the lldb logs, the program exits as soon as it receives SIGPIPE, so Pi doesn't have a handler for SIGPIPE, which causes it to exit. Conclusion Debugging a seemingly trivial terminal UI issue led us into a rabbit hole of standard streams, pipes, Unix processes, and their dynamic behavior on system signals with respect to their parent, and finally to the problems caused by blocking I/O in a UI and how async Rust can fix it. ================================================================================ ## Blog Post: Ship it up (https://tiles.run/blog/ship-it-up) Published: 2026-04-05 Author: Anandu Pavanan @madcla.ws Author URL: https://bsky.app/profile/madcla.ws Description: How we package and ship Tiles Content: We ship Tiles as a tar.gz tarball and as a native macOS .pkg. Either format follows the same broad steps. Assemble the deliverable: Package the Tiles binary and the Python venvstack artifacts into one installer payload. Run the installer: Copy the Tiles binary and Python artifacts into the correct locations on disk. Run postinstall scripts. In early releases, the tarball was the only install path. It served us well, but it had clear limits. Because the release artifact is a gzip tarball, we cannot codesign, notarize, and staple the archive itself the way we can a full installer. We run those steps on the Tiles binary only, not on the entire .gz file. Installation relies on a curl-based script. That is workable for developers and rougher for everyone else. The flow leaves little room to tailor copy, branding, or steps in the installer UI. We wanted a path that fits Apple's signing and notarization story and feels native on macOS. Installers ship as .dmg or .pkg bundles; we chose .pkg because it can run scripts, uses a familiar installer UI, and supports customization with simple HTML. What follows is how we build that .pkg for Tiles. Install file structure The layout matches the directory tree above. When we build the package, we point the tooling at this pkgroot directory as the install root. The installer copies that tree onto the destination volume and creates intermediate directories as needed. For each release, we build a fresh Tiles binary into pkgroot/usr/local/bin and place the remaining updated artifacts under pkgroot/usr/local/share/tiles/. The build script in the repo has the full sequence. Code signing the Tiles binary Code signing gives us: A signed Tiles binary that cannot be altered without invalidating the signature. A signature from a developer certificate that Apple trusts. You need an Apple Developer account and two certificate types: DEVELOPER ID APPLICATION for the binary and DEVELOPER ID INSTALLER for the .pkg. The finished installer wraps the signed binary and the other artifacts in one compressed package. For creating and exporting those certificates, the CodeVamping macOS pkg installer article covers the details. Signing the Tiles binary codesign --force \ --sign "$DEVELOPER_ID_APPLICATION"\ --options runtime \ --timestamp \ --strict \ "${CLI_BIN_PATH}/tiles" The snippet signs the Tiles CLI. $DEVELOPER_ID_APPLICATION is an environment variable that holds the common name of the Developer ID Application certificate. Scripts Bash scripts can run before and after the payload is laid down. We keep preinstall and postinstall scripts in a directory and pass that path into pkgbuild. The Tiles repo has those scripts; they handle cleanup and internal setup. Building the Tiles package With the signed Tiles binary and the rest of the install tree under pkgroot, we run: pkgbuild --root pkgroot --scripts \ pkg/scripts --identifier com.tilesprivacy.tiles --version "$VERSION" \ pkg/tiles-unsigned.pkg --root is pkgroot; --scripts points at the directory from the previous section. Customizing the installer Opening the unsigned package from the previous step shows Apple's default, minimal flow. We layer on welcome and conclusion screens, a logo, and other panels with an Apple distribution definition in XML. That file references HTML for the welcome, conclusion, and other supported steps. Our distribution_network.xml is the working example. Elements such as and point at resources we keep alongside the definition and pass into the final productbuild invocation. productbuild \ --distribution pkg/distribution_network.xml \ --resources pkg/resources \ --package-path pkg/ \ pkg/tiles-dist-unsigned.pkg productbuild reads the unsigned package and writes a distributable installer with those customizations baked in. Code signing the complete installer productsign \ --sign "$DEVELOPER_ID_INSTALLER" \ pkg/tiles-dist-unsigned.pkg \ pkg/tiles.pkg That signs the .pkg itself. The Tiles binary is already signed; signing a macOS binary and signing an installer package are different operations. The main difference is productsign instead of codesign, and the certificate we use is DEVELOPER ID INSTALLER instead of DEVELOPER ID APPLICATION . Notarizing the installer Notarization lets Apple scan the payload for malware. We upload the installer; when processing finishes, the service returns acceptance or rejection. Submission looks like this: xcrun notarytool submit pkg/tiles.pkg \ --keychain-profile "tiles-notary-profile" \ --wait tiles-notary-profile is the keychain entry name so we do not pass Apple ID details on every run. Store the profile once with: xcrun notarytool store-credentials \ "tiles-notary-profile" \ --apple-id "john.doe@gmail.com" \ --team-id "X****4" \ --password "**---**" Stapling the installer Stapling embeds the notarization ticket in the installer file so Gatekeeper needs fewer round trips to Apple when a user opens the package. xcrun stapler staple pkg/tiles.pkg What's next We also ship a fully offline installer that bundles OpenAI's gpt-oss 20B model, so Tiles can be installed without an internet connection. We are working toward making Tiles itself portable, allowing users to carry their model and data and run it from a flash drive on any compatible system. The installer requires Rosetta; on Apple Silicon Macs, it is not included by default and must be installed separately. Rosetta translates Intel binaries to run on Apple Silicon. There is a workaround for this, described in the linked GitHub issue. ================================================================================ ## Blog Post: Move Along, Python (https://tiles.run/blog/move-along-python) Published: 2026-02-17 Author: Anandu Pavanan @madcla.ws Author URL: https://bsky.app/profile/madcla.ws Description: Deterministic, portable Python runtimes for Tiles using layered venvstacks Content: We have been working on Tiles. Tiles is a local-first private AI assistant that runs on-device models with encrypted P2P sync, keeps your data and identity yours, and supports sharing chats with ATproto. To ensure its Python model server starts predictably on any machine, the runtime and dependencies must be deterministic and portable. This post walks through how we achieve that with layered venvstacks. The Python Problem Right now, we have a polyglot architecture where the control plane and CLI are written in Rust, while local model inference runs through a Python server as a daemon. Ideally, when we ship Tiles, we should also ship the required artifacts needed to run Python on the user’s system. Since Python servers cannot be compiled into a single standalone binary, the user’s system must have a Python runtime available. More importantly, it must be a deterministic Python runtime so that the server runs exactly on the version developers expect. In earlier releases of Tiles (before 0.4.0), we packed the server files into the final release tarball. During installation, we extracted them to the user’s system, downloaded uv (a Python package manager), installed Python 3.13 if it was not already present, and then ran the server as a daemon. This approach had several issues: Downloading development-related tools such as uv onto the user’s system Relying on uv at install time to manage dependencies and run the server Increased chances of failures due to dependency or runtime non-determinism Requiring internet access to download all of the above tools Lack of a fully deterministic runtime across operating systems One of the long-term goals of Tiles is complete portability. The previous approach did not align with that vision. Portable Runtimes To address these issues, we decided to ship the runtime along with the release tarball. We are now using venvstacks by LM Studio to achieve this. Venvstacks allows us to build a layered Python environment with three layers: Runtimes\ Defines the exact Python runtime version we need. Frameworks\ Specifies shared Python frameworks such as NumPy, MLX, and others. Applications\ Defines the actual server application and its specific dependencies. Similar to Docker, each layer depends on the layer beneath it. A change in any layer requires rebuilding that layer and the ones above it. All components within a layer share the layers beneath them. For example, every framework uses the same Python runtime defined in the runtimes layer. Likewise, if we have multiple servers in the applications layer and both depend on MLX, they will share the exact deterministic MLX dependency defined in frameworks, as well as the same Python runtime defined in runtimes. How venvstacks is used in Tiles We define everything inside a venvstacks.toml file. Here is the venvstacks.toml used in Tiles. Because we pin dependency versions in the TOML file, we eliminate non-determinism. Internally, venvstacks uses uv to manage dependencies. Once the TOML file is defined, we run: venvstacks lock venvstacks.toml venvstacks build venvstacks.toml venvstacks publish venvstacks.toml These commands resolve dependencies, create the necessary folders, lock files, and metadata for each layer, build the Python runtime and environments based on the lock files, and produce reproducible tarballs that can be unpacked on external systems and run directly. We bundle the venvstack runtime artifacts into the final installer using this bundler script. During installation, this installer script extracts the venvstack tarballs into a deterministic directory. Our Rust CLI can then predictably start the Python server using: stack_export_prod/app-server/bin/python -m server.main What’s Next We tested version 0.4.0 on clean macOS virtual machines to verify portability, and the approach worked well. For now, we are focusing only on macOS. When we expand support to other operating systems, we will revisit this setup and adapt it as needed. Packaging the runtime and dependencies increases the size of the final installer. We are exploring ways to reduce that footprint. We also observed that changes in lock files can produce redundant application tarballs when running the publish command. More details are tracked in this issue. Overall, we are satisfied with this approach for now. ================================================================================ ## Book: Community (https://tiles.run/book/community) # Community ## Get Involved Whether you are already committed to privacy technology or just beginning to reclaim ownership of your computing experience, there are many ways to get involved in the Tiles community. To understand the project goals and architecture, start with: - Install Tiles CLI (/download) and try it out. - Explore the documentation: Tiles Book (https://tiles.run/book) ## Communication and Support If you have questions or want to discuss ideas, you can reach the team and community via: - Discord: https://discord.gg/PPSjcpZzvt - Email: hello@tiles.run (mailto:hello@tiles.run) ## Roadmap Track our progress and see what's coming next on our Roadmap (https://github.com/orgs/tilesprivacy/projects/4). The roadmap outlines our planned features, improvements, and research directions. ## RFCs Join or contribute to the conversation about Tiles design and architecture through Tiles RFC Discussions (https://github.com/orgs/tilesprivacy/discussions). RFCs (Request for Comments) are proposals that introduce major features, architectural changes, or significant new areas of functionality. We welcome community input on these proposals. ## Contributing Thanks for your interest in contributing to Tiles. We welcome contributions of all kinds, including code, documentation, design, and discussion. ### How to Contribute You can contribute in several ways: - Report bugs or request features by opening an issue - Improve documentation or examples - Submit pull requests for bug fixes, refactors, or new features - Open an RFC discussion for proposals that introduce major features, architectural changes, or significant new areas of functionality Before starting work, check the existing issues to avoid duplication and to align with current priorities. If you plan to work on a larger change, open an issue or discussion first to confirm scope and approach. ### Pull Request Guidelines When submitting a pull request: - Keep changes focused and scoped to a single concern - Follow existing code style and conventions - Include clear commit messages and a concise PR description - Reference relevant issues where applicable - Ensure all checks and tests pass New inference backends, memory models, and improvements aligned with the roadmap are especially welcome. ## Community initiatives ### IndiaFOSS 2026 giveaway Tiles Privacy and Sol PBC (https://solpbc.org/) ran an IndiaFOSS 2026 giveaway for OSDC members. Ten selected applicants received conference tickets and swag, and five also received a $100 travel grant. View the archived giveaway form → (/indiafoss-2026-giveaway) ## Development Setup This guide will help you set up a reproducible development environment for Tiles. Tiles supports two environments: prod (production) and dev (development). These instructions assume you are setting up for local development. ### Prerequisites - Rust & Cargo (https://www.rust-lang.org/tools/install) - just (https://github.com/casey/just) (for task management) - Python 3.13 (https://www.python.org/downloads/) - uv (https://docs.astral.sh/uv/) (for fast Python dependency management) - Git (https://git-scm.com/) ### Setup Steps 1. **Clone the repository:** git clone https://github.com/tilesprivacy/tiles.git cd tiles 2. **Install Rust dependencies:** If you're new to Rust, see Rust Install Guide (https://www.rust-lang.org/tools/install). cargo build 3. **Install project task runner:** just (https://github.com/casey/just) provides easy command shortcuts. cargo install just # or use your OS package manager 4. **Set up the Python server environment:** - Make sure uv (https://docs.astral.sh/uv/) is installed: pip install uv - Sync Python dependencies: cd server uv sync cd .. ### Running Tiles (Development) Open two terminal windows: 1. **Terminal 1: Start the server** From the project root: just serve 2. **Terminal 2: Run the Rust CLI** From the root directory: cargo run > **Tip:** Refer to the justfile for additional common commands and automation. For troubleshooting, see CONTRIBUTING.md (https://github.com/tilesprivacy/tiles/blob/main/CONTRIBUTING.md) and open an issue if you need help. ### Building Tiles installer (Development) Install venvstacks (https://github.com/lmstudio-ai/venvstacks?tab=readme-ov-file#installing) for portable py runtime From the project root do: just bundle # Creates the compressed zip in dist/ Set the ENV in install.sh to dev just install Now tiles should be available in PATH ## Code of Conduct By participating in this project, you agree to follow the project's Code of Conduct (https://github.com/tilesprivacy/tiles/blob/main/CODE_OF_CONDUCT.md). Be respectful, constructive, and collaborative in all interactions. We appreciate your time and effort in helping build Tiles. ================================================================================ ## Book: Finances (https://tiles.run/book/finances) # Finances Tiles is developed in the open and funded by its community. We believe a privacy company earns trust through transparency, so our finances are transparent down to individual line items: each month we publish what we earn and what we spend on this page. ## October 2026 Tiles earned no product revenue in October. Sponsorships brought in ₹1,25,000, compensation was ₹1,24,500, and infrastructure expenses were ₹2,800. Anandu Pavanan and Prashant Mishra each contributed ₹10,000 back to the company, and the company pool balance is −₹2,600. | Summary | Amount | | :----------- | --------: | | Revenue | ₹0 | | Sponsorships | ₹1,25,000 | | Compensation | ₹1,24,500 | | Expenses | ₹2,800 | | Company pool | −₹2,600 | ### Revenue Tiles earned no revenue in October. Once income from paid plans arrives, it will be itemized here. ### Sponsorships | Source | Amount | | :-------------- | ------------: | | GitHub Sponsors | ₹1,25,000 | | **Total** | **₹1,25,000** | ### Compensation Each contributor was compensated ₹41,500 in October. Voluntary contributions to the company pool are listed separately below. | Contributor | Compensation | | :--------------------------- | ------------: | | Ankesh Bharti, Founder | ₹41,500 | | Anandu Pavanan, Engineering | ₹41,500 | | Prashant Mishra, Engineering | ₹41,500 | | **Total** | **₹1,24,500** | ### Expenses | Item | Amount | | :--------------------------------------------------- | ---------: | | Cloud Infrastructure (Vercel, Cloudflare R2, GitHub) | ₹2,800 | | **Total** | **₹2,800** | ### Company pool | Shared by | Amount | | :-------------- | ----------: | | Anandu Pavanan | ₹10,000 | | Prashant Mishra | ₹10,000 | | **Total** | **₹20,000** | The company pool balance is −₹2,600. ## September 2026 With no product revenue yet, sponsorships brought in ₹1,35,000 and teammates shared ₹25,000 back into the company pool, while ₹1,37,200 went out in compensation and expenses. After carrying forward August's ₹42,600 deficit, the net balance is −₹19,800. | Summary | Amount | | :----------- | ----------: | | Revenue | ₹0 | | Sponsorships | ₹1,35,000 | | Compensation | ₹1,35,000 | | Expenses | ₹2,200 | | Company pool | ₹25,000 | | **Net** | **−₹19,800** | ### Revenue Tiles earned no revenue in September. Once income from paid plans arrives, it will be itemized here. ### Sponsorships | Source | Amount | | :-------------- | ------------: | | GitHub Sponsors | ₹1,35,000 | | **Total** | **₹1,35,000** | ### Compensation | Contributor | Amount | | :---------------------------- | ------------: | | Ankesh Bharti, Founder | ₹45,000 | | Anandu Pavanan, Engineering | ₹45,000 | | Prashant Mishra, Engineering | ₹45,000 | | **Total** | **₹1,35,000** | ### Expenses | Item | Amount | | :------------------------------------------- | ---------: | | Cloud Infrastructure (Vercel, Cloudflare R2) | ₹2,200 | | **Total** | **₹2,200** | ### Company pool | Shared by | Amount | | :-------------- | ----------: | | Anandu Pavanan | ₹5,000 | | Prashant Mishra | ₹20,000 | | **Total** | **₹25,000** | ## August 2026 With no product revenue yet, sponsorships brought in ₹1,75,000 and teammates shared ₹25,000 back into the company pool, while ₹2,42,600 went out in compensation and expenses. The company ran at a deficit of ₹42,600 this month. | Summary | Amount | | :----------- | --------: | | Revenue | ₹0 | | Sponsorships | ₹1,75,000 | | Compensation | ₹1,35,000 | | Expenses | ₹1,07,600 | | Company pool | ₹25,000 | | **Net** | **−₹42,600** | ### Revenue Tiles earned no revenue in August. Once income from paid plans arrives, it will be itemized here. ### Sponsorships | Source | Amount | | :-------------------------------------------------------------- | --------: | | GitHub Sponsors | ₹1,35,000 | | One-time contribution from Jeremie, toward company registration | ₹40,000 | | **Total** | **₹1,75,000** | ### Compensation | Contributor | Amount | | :--------------------------- | --------: | | Ankesh Bharti, Founder | ₹45,000 | | Anandu Pavanan, Engineering | ₹45,000 | | Prashant Mishra, Engineering | ₹45,000 | | **Total** | **₹1,35,000** | ### Expenses | Item | Amount | | :------------------------------------- | --------: | | Yearly virtual office rent | ₹41,000 | | Incorporation agency fees | ₹35,000 | | Government fees & compliance | ₹18,500 | | Yearly Apple Developer Program Membership | ₹8,700 | | Domain renewals | ₹2,200 | | Cloud Infrastructure (Vercel, Cloudflare R2) | ₹2,200 | | **Total** | **₹1,07,600** | ### Company pool | Shared by | Amount | | :-------------- | ------: | | Anandu Pavanan | ₹5,000 | | Prashant Mishra | ₹20,000 | | **Total** | **₹25,000** | ## Frequently asked questions All figures are in Indian Rupees. Tiles Privacy Technologies Pvt. Ltd. is registered in Bengaluru, India. Our mission is to build software that gives people greater agency, control, and choice in their digital lives. We believe that privacy adoption at scale must work backwards from preserving utility. This means negligible impact on user experience, model intelligence, throughput, latency, tool use & agentic capabilities, and web access. Funds are used to compensate contributors, cover infrastructure, and pay the administrative costs of running the company. We are not beholden to commercial interests or investor pressure: the work is paid for by the people who want it to exist. If you would like to help keep it going, you can sponsor Tiles (https://tiles.run/sponsor). Contributors who have consistently demonstrated high-quality work and friendly behavior in the Tiles community may be invited to enter into a paid contributor contract. Everyone on the team receives the same flat compensation, regardless of role. Contributors may voluntarily share part of their compensation back into the company pool; that money flows back into the runway, so it counts toward the net. Contributors maintain full autonomy over when they work and which tasks they choose to pursue. By the time someone is offered a contract, they have already shown sound judgment about what meaningfully advances the project, and we trust them to continue using that judgment. All contributor contracts are issued at the discretion of the project lead. The project continues to follow a BDFL (https://en.wikipedia.org/wiki/Benevolent_dictator_for_life) model, with Ankesh Bharti serving as the project lead and final authority on all decisions, including the direction of funds within the company (in accordance with the mission statement (https://tiles.run/mission) and legal requirements). The project remains licensed under the MIT license, and the rights and permissions granted by that license remain unchanged. ================================================================================ ## Book: Tiles Book (https://tiles.run/book) # Book Technical documentation covering the models, infrastructure, and cryptography behind Tiles, the consumer product, and Tilekit, the developer-facing SDK written in Rust. AI / LLM agents: For a machine-readable summary of this site, see /llms.txt (/llms.txt) or /llms-full.txt (/llms-full.txt). ================================================================================ ## Book: Licenses (https://tiles.run/book/licenses) # Licenses Tiles Plus and Tiles Pro are the paid licenses, and they fund independent development. ## Overview - **Free**: limited private web searches, every client side feature that runs locally, and shared chats on the web. - **Tiles Plus**: $4 USD per user, per month, covering sync and collaboration across devices from anywhere. - **Tiles Pro**: $15 USD per user, per month, covering everything in Tiles Plus along with the private services we host on your behalf. - **Commercial use**: covered on every tier, including Free. ## Tiles Plus ### Payment - Price: **$4 USD** - Cadence: **per user, per month** - Checkout: Subscribe to Tiles Plus (https://buy.polar.sh/polar_cl_cIV2Vl0K60hJzHJqoOCrvd2xYuQtECY6PPlPy4gdoxp) ### What it includes - Sync across networks using end-to-end encrypted relays - Remote inference for local models across devices ## Tiles Pro ### Payment - Price: **$15 USD** - Cadence: **per user, per month** - Checkout: Subscribe to Tiles Pro (https://buy.polar.sh/polar_cl_3LyXhxgqyNTiHERg0sdzEzKM7Z7jRxsFFH24d3asCns) - Bulk purchases: support@tiles.run (mailto:support@tiles.run) ### What it includes - Unlimited private web searches - Run cloud models with confidential compute - Managed public relays - Data backup and key recovery ### Your license key Tiles Pro is delivered as a **license key**, issued automatically by Polar at checkout and revoked when a subscription ends. There is no account to create. - Find your key in the receipt email or the customer portal (https://polar.sh/tilesprivacy/portal/). ## Polar checkout details Tiles purchases are processed through Polar (https://polar.sh), which acts as merchant of record on behalf of Tiles Privacy Technologies Pvt. Ltd. Card details are handled by Polar and never reach us. ### Customer portal After checkout, you can manage your license key, subscription renewals, billing, and related purchase details in Polar’s customer portal. Sign in and self-serve updates there: https://polar.sh/tilesprivacy/portal/ (https://polar.sh/tilesprivacy/portal/) ## Notes - Tiles Plus and Tiles Pro can be cancelled at any time and run to the end of the paid period. - License purchases support the long-term independence of Tiles. ================================================================================ ## Book: Manual (https://tiles.run/book/manual) # Manual ## Command Line Options Commands match the groups shown in tiles help: **Getting Started**, **Accounts**, **Sync**, **System**, and **Tools**. ## Getting Started ### Main command (tiles) Launches onboarding (first run) and the interactive chat. tiles # Onboarding (if needed) and interactive chat ### Run models (tiles run) Run a Modelfile (uses the default model if none is provided). tiles run [MODELFILE_PATH] # Default model if path omitted The same optional flags below also apply when you run tiles without a subcommand. tiles run tiles run ./path/to/Modelfile Optional tuning flags: tiles run --context-length 8192 tiles run --gpu-layers 32 tiles run --offload-kqv tiles run --offload-kqv false tiles run --batch-size 512 **--context-length **: Context window for local inference. **--gpu-layers **: Number of model layers to offload to the GPU. **--offload-kqv []**: Offload K/Q/V attention operations (true or false). **--batch-size **: Prompt processing batch size. Values you set on the command line are persisted in config.toml and apply on later runs. Create a new Modelfile by adding a plain text file named Modelfile: FROM unsloth/gemma-4-12b-it-GGUF SYSTEM You are Mario from Super Mario Bros, acting as an assistant. Tiles uses llama.cpp (https://github.com/ggml-org/llama.cpp) for local inference on supported platforms. Use a GGUF model hosted on Hugging Face in the FROM field. We are working on adding more model path sources in FROM, including local paths. Learn more in the Tilekit Modelfile reference (/book/tilekit). ### Help (tiles help) Show the top-level help menu or help for a specific command. tiles help tiles help run tiles help link tiles help plugin ## Accounts ### Account (tiles account) Manage your user account: root identity and display nickname. tiles account create [] # Create root identity (nickname optional) tiles account set-nickname # Set nickname tiles account # Show account details tiles account create alice tiles account set-nickname alice tiles account ### ATproto (tiles at) ATproto-related commands. ATproto is currently used to share chat sessions. - tiles at login : log in with your ATproto handle (for example, alice.bsky.social) via browser OAuth. - tiles at logout: log out of the current ATproto account. tiles at login alice.bsky.social tiles at logout Authentication currently uses a localhost callback (127.0.0.1:8988), and session state is stored locally in the Tiles database. ### Data (tiles data) Configure your data and storage paths. tiles data set-path # Set data folder tiles data set-path ~/.tiles/data ## Plugins ### Plugins (tiles plugin) Tiles plugins follow the open Agent Plugins standard (https://agent-plugins.org/), a portable package format for reusable components that extend AI agents. tiles plugin install # Install from a URL or local archive tiles plugin uninstall # Remove an installed plugin tiles plugin list # List installed plugins **tiles plugin install **: Install a plugin from a hosted URL or from a local .zip or .tar.gz file on disk. Verified Tiles plugins are listed at tiles.run/plugins (https://tiles.run/plugins). **tiles plugin uninstall **: Remove an installed plugin by name. **tiles plugin list**: List installed plugins. Tiles installs plugins from .zip or .tar.gz archives, either downloaded from a URL or available on the local filesystem. The Agent Plugins standard defines the package contents; Tiles manages installation and distribution. ### Using plugins In the Tiles CLI chat, type @ followed by a plugin name and your request: @exa Find the latest research on local-first software @caldir What is on my calendar tomorrow? Run tiles plugin list to see installed plugin names. Restart Tiles after installing or enabling a plugin so it becomes available in chat. Tiles can also use an enabled plugin automatically when it matches your request. ### Plugin package layout plugin-name/ ├── plugin.json ├── skills/ │ └── skill-name/ │ ├── SKILL.md │ ├── scripts/ │ └── references/ ├── mcp.json └── com.example.client/ └── ... Every Agent Plugin has a root plugin.json manifest. The skills/ directory contains Agent Skills (https://agentskills.io/specification), mcp.json describes MCP servers, and reverse-domain directories hold client-specific extensions. All components except plugin.json are optional. A minimal manifest identifies the standard version and plugin name: { "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "plugin-name" } See the Agent Plugins authoring guide (https://agent-plugins.org/plugin-authors/build-an-agent-plugin) for the complete portable format. Learn how to use plugins (#using-plugins) in chat. ## Sync Peer-to-peer sync has two steps. **Link** devices first (consent): one device creates a token, the other accepts it. Then **sync** chats between linked peers. Online and same-local-network offline linking use the same commands; Iroh handles transport, and mDNS can discover peers without internet. ### Link devices (tiles link) tiles link create # Start a link toward a peer and print a token tiles link add # Accept the token on the other device tiles link list-peers # List linked peers by DID and nickname tiles link revoke # Unlink a peer Run tiles link create on one device, using the other device's DID, and share the printed token out of band. On the other device, run tiles link add . Online tokens are **UCAN**s (for example, ucan:eyJ...YzQ); on the same local network without internet, the token is an **eight-character alphanumeric code**. **tiles link revoke **: Unlinks a peer; their future sync requests are ignored. ### Sync chats (tiles sync) After devices are linked, one device listens while the other starts sync toward the listener's DID. tiles sync # Listen for a sync request tiles sync # Start sync with a linked peer Run tiles sync on the receiving device. On the other device, run tiles sync (get the DID from tiles link list-peers). When a sync run finishes, both devices should show a notification.
### Remote inference (tiles remote) Share inference from one of your devices to another over Iroh. This is useful when a remote machine has the model or GPU you want, while your primary machine keeps the interactive Tiles session. # Remote machine tiles server start # Starts the inference server in background tiles remote share # Generates an Iroh ticket # Device using remote inference tiles --remote # Uses remote machine inference **tiles server start** starts the inference server on the remote machine before sharing it. **tiles remote share** starts sharing the remote machine's inference endpoint and prints an Iroh ticket. **tiles --remote ** runs on the device intending to use remote inference, while inference happens on the remote machine. tiles remote status # Check remote inference sharing status tiles remote unshare # Stop sharing remote inference ## System ### App updates (tiles update) Update Tiles to the latest version. tiles update # Check for and install app updates ### Health (tiles health) Check the status of dependencies. tiles health ### Inference server (tiles server) Configure the inference server. tiles server start # Start the inference server tiles server stop # Stop the inference server tiles server daemon true # Keep inference running after the REPL exits tiles server daemon false # Stop inference when the REPL exits (default) **tiles server daemon [FLAG]** configures whether inference runs in the background. FLAG is true or false. When true, closing the REPL does not stop inference. The setting is stored under [inference] daemon in config.toml. ### Daemon (tiles daemon) Configure daemon behavior. tiles daemon start # Start the daemon (auto-starts when you run tiles) tiles daemon start 1729 # Start the daemon on a custom port tiles daemon stop # Stop the daemon ## Slash commands Slash commands give you fast, keyboard-first control over Tiles in interactive chat. Type /? or /help in the prompt to open available commands and quickly run actions like checking session state, resuming prior sessions, and sharing chats without leaving the terminal. Use /bye to exit the chat session. ### Session Commands #### /status Show the current session state. #### /sessions List available sessions in local storage.
#### /resume Resume a specific session by ID. ### Sharing Commands These commands require an active ATproto login. See ATproto (tiles at) (#atproto-tiles-at). #### /share (via ATproto) Create a shareable link for the current session.
#### /share (via ATproto) Create a shareable link for a specific session. Example shared session link: chat.tiles.run/YXQ6Ly9k...ZTJr (https://chat.tiles.run/YXQ6Ly9kaWQ6cGxjOnZreGY2aTY1a2VoZmY2a2p3cjNjaDJ2eC9ydW4udGlsZXMuc2Vzc2lvbi8zbW9vYmNjeXNnZTJr). ### Using Skills Agent Plugins can include skills under skills/. Tiles can also use available skills automatically during a conversation when appropriate. #### /skills List available skills from installed plugins.
#### @ Run a skill directly with @ followed by your request (for example, @my-skill Deploy the site). ## Uninstall Tiles Use tiles uninstall to uninstall Tiles from the system. tiles uninstall By default, it keeps the user data folder, downloaded models, and config.toml, so chats, memory, databases, logs, local settings, and model files remain for a later reinstall. For a complete cleanup, pass --all: tiles uninstall --all ================================================================================ ## Book: Models (https://tiles.run/book/models) # Models Tiles is designed for everyday productivity tasks. It combines a carefully tested model, inference parameters, and agent harness, so users do not have to manage model selection, tuning, or scaffolding themselves. Tiles uses Google’s Gemma logogemma4-12b (https://ai.google.dev/gemma/docs) as the default model for everyday tasks. We use Unsloth’s Dynamic 2.0 GGUF (https://huggingface.co/unsloth/gemma-4-12b-it-GGUF) release of Gemma 4 12B and enable first-party Multi-Token Prediction (MTP) (https://unsloth.ai/docs/models/mtp) speculative decoding out of the box, reducing decoding latency while preserving the target model’s output quality. Tiles uses llama.cpp (https://github.com/ggml-org/llama.cpp) for local inference across supported platforms, with a common inference stack built around GGUF models. Tiles targets everyday personal machines with at least 16 GB of system memory for real productivity tasks. ================================================================================ ## Book: Open source (https://tiles.run/book/opensource) # Open source Tiles is fully open source and built on open-source software. In some cases, we maintain forks to ship features the way we want or fix blocking bugs. We intend to upstream these changes whenever possible. ## Forks we maintain | Fork | Upstream | Description | Link | | --- | --- | --- | --- | | tilesprivacy/tiles-pi | earendil-works/pi (https://github.com/earendil-works/pi) | Pi fork for Tiles. | tiles-pi (https://github.com/tilesprivacy/tiles-pi) | | tilesprivacy/dialog-db | dialog-db/dialog-db (https://github.com/dialog-db/dialog-db) | Embeddable database for local-first software. | dialog-db (https://github.com/tilesprivacy/dialog-db) | ## Upstream dependencies Tiles utilizes the following open-source software. We are thankful to the developers and maintainers of these libraries! | Library/Resource | Description | License | Link | | --- | --- | --- | --- | | ggml-org/llama.cpp | Inference engine for running large language models locally on Linux. | MIT | llama.cpp (https://github.com/ggml-org/llama.cpp) | | earendil-works/pi | AI agent toolkit with a unified LLM API, agent loop, TUI, and coding-agent CLI. | MIT | pi (https://github.com/earendil-works/pi) | | n0-computer/iroh | Modular peer-to-peer networking stack in Rust for distributed apps. | Apache-2.0 | iroh (https://github.com/n0-computer/iroh) | | sqlcipher/sqlcipher | Standalone SQLite fork with AES-256 encryption and other database security features. | BSD-3-Clause | SQLCipher (https://github.com/sqlcipher/sqlcipher) | | rusqlite/rusqlite | Ergonomic bindings to SQLite for Rust. | MIT | rusqlite (https://github.com/rusqlite/rusqlite) | | ucan-wg/rs-ucan | Rust implementation of UCAN. | Apache-2.0 | rs-ucan (https://github.com/ucan-wg/rs-ucan) | | huggingface/hf-hub | Rust client for the Hugging Face Hub. | Apache-2.0 | hf-hub (https://github.com/huggingface/hf-hub) | | mozilla-ai/openresponses-python | Python SDK for the OpenResponses specification. | Apache-2.0 | openresponses-python (https://github.com/mozilla-ai/openresponses-python) | | openresponses/openresponses | Open specification for multi-provider, interoperable LLM interfaces. | Apache-2.0 | OpenResponses (https://github.com/openresponses/openresponses) | | unsloth/gemma-4 | Unsloth's builds of Google's Gemma 4 open model family for local inference. | Gemma | gemma-4 (https://huggingface.co/collections/unsloth/gemma-4) | | lmstudio-ai/venvstacks | Virtual environment stacks for Python. | MIT | venvstacks (https://github.com/lmstudio-ai/venvstacks) | This list is still a work in progress and will be updated as we continue to add more features and dependencies to Tiles. ================================================================================ ## Book: Overview (https://tiles.run/book/overview) # Overview We make two things: Tiles, our consumer product, a local-first AI assistant; and Tilekit, the SDK for developers to build on the infrastructure behind Tiles. **Status: Alpha** Tiles is currently alpha-quality software. It is usable for everyday tasks, though you may encounter bugs and performance issues. Tilekit, the developer SDK, is experimental, not a current priority, and intended for exploratory use, not production.
## What makes Tiles different Tiles is built around a narrow bet: one well-integrated model at a time, optimized for credible local inference on Apple Silicon while balancing privacy, capability, and everyday usability. ## Appendix ### Technical Architecture
Technical architecture diagram for Tiles
Technical architecture of Tiles.
### Shared Links View this public shared chat example at chat.tiles.run/YXQ6Ly9k...ZTJr (https://chat.tiles.run/YXQ6Ly9kaWQ6cGxjOnZreGY2aTY1a2VoZmY2a2p3cjNjaDJ2eC9ydW4udGlsZXMuc2Vzc2lvbi8zbW9vYmNjeXNnZTJr), or this private shared chat example at chat.tiles.run/YXQ6Ly9k...DTBVLJ (https://chat.tiles.run/YXQ6Ly9kaWQ6cGxjOnZreGY2aTY1a2VoZmY2a2p3cjNjaDJ2eC9ydW4udGlsZXMuc2Vzc2lvbi8zbXBvcWd0d3p5ZzJ6#kUU4azu7HkPh7eqq5TQ8/YnAKHsBLIri.9wFnPDTBVLJDrOOkhidewMzYzZS8QAPkeQW7ozlYGVU=). Tiles supports public and private shared chat links. Public links resolve to a chat record on the user's ATproto personal data server (PDS). Private links store an encrypted transcript on the user's PDS; the decryption key is appended to the share URL and is not sent to the server. In both cases, Tiles does not store a copy of the shared conversation on our servers. ## Frequently asked questions
Short answers drawn from our security documentation (/book/security). For full context and limits, read that page.
Tiles is currently alpha-quality software. It is usable for everyday tasks, though you may encounter bugs and performance issues. Tilekit, the developer SDK, is experimental, not a current priority, and intended for exploratory use, not production. Tiles is designed so the default experience runs on-device. The local server binds to localhost, which limits exposed network surface during normal use. Configuration and application data live in standard local directories, and you can change the user data path when needed. No. Application state is persisted locally with encryption at rest. The Rust build uses SQLCipher-enabled SQLite, and database connections use a passkey from secure storage. That raises the bar against casual inspection of copied files, though it does not remove all local risk. Public identity is separated from private keys. Device and account identity use did:key identifiers from Ed25519 keys. Private keys and database passkeys are stored in the operating system's secure credential store, not in plaintext app configuration files. Peer-to-peer linking is user-mediated, not automatic. One device shows a ticket or local code; the other enters it and explicitly accepts or rejects. In release builds, endpoints derive from your stored secret key, and peer identity is checked against the delivered public key. Sync includes defensive controls, including a maximum size cap for downloaded deltas before they are applied. Sync uses Iroh (https://www.iroh.computer/) for device-to-device networking. When a direct path is not practical, Iroh's public relays can help establish the connection; we list that relay use on our sub-processors (/sub-processors) page. The product does not currently bundle obvious analytics SDKs such as Sentry, PostHog, Segment, Mixpanel, or similar telemetry. There is still local logging: the Python server may log request metadata and bodies to files under the Tiles data directory, so prompt content can appear in local logs unless logging changes. Updates can check GitHub releases and install via the hosted installer script, which depends on release and hosting integrity rather than a stronger built-in end-user verification workflow. Dependencies are pinned and reviewed. The macOS package is code signed, notarized, and stapled. Bundled dependencies are self-contained so normal installation and use do not require live package downloads from the internet. Use the published security policy and private disclosure path. Researchers can use GitHub Security Advisories or email security@tiles.run (mailto:security@tiles.run), with expectations for acknowledgement, triage, and coordinated disclosure. See SECURITY.md (https://github.com/tilesprivacy/tiles/blob/main/SECURITY.md). ================================================================================ ## Book: Research (https://tiles.run/book/research) # Research ================================================================================ ## Book: Security (https://tiles.run/book/security) # Security Tiles is designed around a local-first model. The goal is simple: keep personal context, identity, and memory under user control by default. Tiles is still in alpha. Some parts of the system are already stable enough to describe clearly, while others are still being hardened. **Personal assistant trust model:** this guidance assumes one trusted operator boundary per device or gateway. Tiles is not a hostile multi-tenant boundary for adversarial users sharing one agent or gateway. If you need mixed-trust operation, split trust boundaries with separate gateways, credentials, OS users, or hosts. Inference runtime hardening with Stage-2 hypervisor memory isolation and hardware-backed attestation is on our roadmap, enabling multi-tenant use cases out of the box. ## Local-First Architecture The default experience runs on-device. The local server binds to localhost, and app data lives in standard local directories with support for a custom user data path. ## Local Data Protection Tiles encrypts local SQLite databases at rest. The Rust application uses SQLCipher-enabled SQLite, and database connections are opened with a passkey retrieved from secure storage. That does not remove all local risk, but it does raise the bar against casual inspection of copied database files. ## Identity and Secret Storage Device and account identity are based on did:key identifiers derived from Ed25519 keys. Private keys and database passkeys are stored in the operating system credential store rather than in app-managed plaintext configuration. ## Peer Linking and Sync Tiles includes peer-to-peer device linking and chat sync. Linking is user-mediated: one device presents a ticket or local code, and the other side explicitly accepts or rejects it. Sync is limited to linked peers and bounded by a maximum downloaded delta size before processing. ### Iroh Relay and Sync Transport Tiles sync uses Iroh endpoints, gossip topics, and blob tickets. In normal online operation, alpha builds rely on public Iroh relay infrastructure. On local networks, Tiles can fall back to mDNS for nearby discovery. The long-term plan is to move online relay infrastructure under direct Tiles control. ## Memory and Restricted Code Execution Tiles currently includes a memory-agent flow that can execute generated Python against a designated memory path. That path has file-operation restrictions and basic size limits, but it is not a hardened sandbox and should not be described as strong isolation. This part of the system is transitional and not the long-term model for agent execution. ## Logging and Operational Boundaries Tiles does not currently ship obvious built-in product analytics SDKs such as Sentry, PostHog, Segment, or Mixpanel. At the same time, the local Python server writes logs inside the Tiles data directory, and those logs may include request metadata, prompts, and request bodies. ## Updates and Supply Chain Trust Tiles checks GitHub releases for updates and can install updates through a hosted installer script. That is convenient, but it is also a trust boundary. The current updater depends on the integrity of the Tiles release process and installer hosting rather than on a stronger built-in end-user verification flow. Dependencies are pinned and reviewed before they are added. The macOS installer is code signed, notarized, and stapled. Tiles is also packaged with self-contained dependencies so normal installation does not depend on live package downloads. ## Vulnerability Disclosure We publish a security policy and private disclosure path for vulnerabilities. Reports should go through GitHub Security Advisories or security@tiles.run (mailto:security@tiles.run). See SECURITY.md (https://github.com/tilesprivacy/tiles/blob/main/SECURITY.md). ## Current Strengths - Local-first execution model with a localhost-bound application server - Encrypted local databases for persisted account and chat data - OS-backed secret storage for identity keys and database passkeys - Device identity based on cryptographic keys instead of a required centralized account - Explicit user approval during peer linking - Defensive bounds on synced payload size - Published vulnerability disclosure process ## Current Limits - Local server logs may include prompt and request content - Agents are not sandboxed today - The memory execution environment is restricted, but not strongly isolated - Offline pairing codes are still an evolving part of the linking model - The update path is convenient, but remains a privileged remote installation flow - Some transport-level guarantees depend on upstream networking components and are not yet explained in dedicated project documentation ## Summary Tiles already implements several concrete privacy and security controls: local-first operation, encrypted local persistence, OS-backed secret handling, and explicit peer-to-peer linking. At the same time, the project still has meaningful trust boundaries and hardening work ahead. Tiles should not be described as trustless. It should be described as software that keeps more sensitive state local by default and makes key security decisions more visible to the user. ================================================================================ ## Book: Tilekit (https://tiles.run/book/tilekit) # Tilekit Tilekit provides REST APIs for integrating Tiles into local clients and custom UIs. The endpoints run in the Tiles daemon under /v1/tilekit/ and cover inference server controls, the Pi agent, sessions, accounts, and ATproto.

REST API

Use the Tiles daemon’s local REST API to integrate sessions, inference, and accounts into your client. Expand an endpoint to see its request fields, curl example, and response details. Fetch in Bruno **Base URL** http://127.0.0.1:1729/v1/tilekit Run the Tiles daemon first. For chat, start the inference server, create a session, then send a prompt with the returned session ID. The endpoints below follow the current daemon source; availability depends on your installed Tiles version. **Responses** JSON success responses use {"status":"success","data":...}. Application errors use {"status":"failed","reason":"..."} with an HTTP error status. Malformed requests may be rejected before reaching a handler. The prompt endpoint returns an SSE stream. ## Server Manage the local inference server. Source (https://github.com/tilesprivacy/tiles/blob/canary/tiles/src/daemon/server.rs). Start the inference server in the background. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/server/start" **Response** Returns a status message in data.message. Stop the inference server. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/server/stop" **Response** Returns a status message in data.message. Check whether the inference server is responding. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/server/ping" **Response** Returns the health-check message in data.message. ## Agent Work directly with the Pi agent. Create a session before sending prompts. Source (https://github.com/tilesprivacy/tiles/blob/canary/tiles/src/daemon/agent.rs). Start the Pi agent if it is not already running. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/agent/start" **Response** Returns data.message indicating whether the agent started or was already running. Read the running agent’s current state. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/agent/state" **Response** Returns the Pi agent state in data. An agent must already be running. Send a message to the running agent. The response streams Server-Sent Events (SSE). **JSON body** | Field | Type | Required | Description | | --- | --- | --- | --- | | message | string | Required | Prompt to send to the agent. | | session_id | string | Optional | Session ID used to record the turn for sharing. | **Example request** curl -N -X POST "http://127.0.0.1:1729/v1/tilekit/agent/prompt" \ -H 'Content-Type: application/json' \ -d '{ "message": "Hello!", "session_id": "YOUR_SESSION_ID" }' **Response** Returns text/event-stream, rather than the JSON success envelope. curl -N displays events without buffering. Omitting session_id runs the turn without recording a session snapshot. End the current agent session gracefully. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/agent/end_session" **Response** Returns a confirmation in data.message. Restart the agent using its current configuration. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/agent/reload" **Response** Returns a confirmation in data.message. ## Session Create sessions and work with locally stored chats. Source (https://github.com/tilesprivacy/tiles/blob/canary/tiles/src/daemon/session.rs). Create a new session, starting the Pi agent if needed. Start the inference server before sending prompts. **Request body:** None. **Example request** curl -X POST "http://127.0.0.1:1729/v1/tilekit/session/new" **Response** Returns the session ID in data.id. Pass this value as session_id when sending a prompt. List sessions stored in the local chat database. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/session/list" **Response** Returns the stored sessions in data. Fetch the stored chats for a session. **Path parameter** session_id · string · required. Replace YOUR_SESSION_ID in the example with the session ID. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/session/YOUR_SESSION_ID/chats" **Response** Returns the session chat data in data. Save a message to the local chat database. The user ID must identify an existing local user. **JSON body** | Field | Type | Required | Description | | --- | --- | --- | --- | | text | string | Required | Message content. | | session_id | string | Required | Session to save the message in. | | role | string | Required | One of system, user, assistant, developer, or toolResult. | | user_id | string | Required | Existing local user ID. | | model_used | string | Required | Model associated with the message. | | parent_chat_id | string | Optional | Parent message ID. | **Example request** curl -X POST "http://127.0.0.1:1729/v1/tilekit/session/chat" \ -H 'Content-Type: application/json' \ -d '{ "text": "Hello!", "session_id": "YOUR_SESSION_ID", "role": "user", "user_id": "YOUR_USER_ID", "model_used": "YOUR_MODEL" }' **Response** Returns the saved chat in data. A user message can create a stored session when that session does not yet exist. ## Account Create and inspect the local Tiles account. Source (https://github.com/tilesprivacy/tiles/blob/canary/tiles/src/daemon/account.rs). Create a local account for onboarding. **JSON body** | Field | Type | Required | Description | | --- | --- | --- | --- | | nickname | string | Required | Display nickname for the account. | **Example request** curl -X POST "http://127.0.0.1:1729/v1/tilekit/account/create" \ -H 'Content-Type: application/json' \ -d '{ "nickname": "alice" }' **Response** Returns the account result in data. Read the current local account details. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/account/status" **Response** Returns the local account in data. Returns 404 when no local account exists. ## ATproto Connect an ATproto account and publish session snapshots. Source (https://github.com/tilesprivacy/tiles/blob/canary/tiles/src/daemon/atproto.rs). Begin ATproto login for the supplied handle. **JSON body** | Field | Type | Required | Description | | --- | --- | --- | --- | | user_handle | string | Required | ATproto account handle. | **Example request** curl -X POST "http://127.0.0.1:1729/v1/tilekit/atproto/login" \ -H 'Content-Type: application/json' \ -d '{ "user_handle": "alice.bsky.social" }' **Response** Returns the login result in data after the login flow completes. Log out of the connected ATproto account. **Request body:** None. **Example request** curl -X POST "http://127.0.0.1:1729/v1/tilekit/atproto/logout" **Response** Returns the logout result in data. Read the connected ATproto account. **Request body:** None. **Example request** curl -X GET "http://127.0.0.1:1729/v1/tilekit/atproto/status" **Response** Returns data.handle and data.did. Returns 404 when not logged in. Publish a stored session to the connected account’s PDS and return a share link. This writes a record each time it is called. **Path parameter** session_id · string · required. Replace YOUR_SESSION_ID in the example with the session ID. **JSON body** | Field | Type | Required | Description | | --- | --- | --- | --- | | is_private | boolean | Optional | Defaults to false. Use true to encrypt the shared session. | **Example request** curl -X POST "http://127.0.0.1:1729/v1/tilekit/atproto/share-session/YOUR_SESSION_ID" \ -H 'Content-Type: application/json' \ -d '{ "is_private": true }' **Response** Returns data.url and data.is_private. Requires an ATproto login and an existing stored session. ## Source and tooling Open docs/apis in **Bruno**, select the Tilekit collection, and use its dev environment. It sets tilekit_base_url to the local base URL above. - Bruno collection and runnable requests (https://github.com/tilesprivacy/tiles/tree/canary/docs/apis/tilekit%20apis) - Daemon route definitions and handlers (https://github.com/tilesprivacy/tiles/tree/canary/tiles/src/daemon) - API design overview (https://github.com/tilesprivacy/tiles/blob/canary/docs/adr/tilekit.md) The daemon route definitions are authoritative. The design overview includes planned endpoints and older names, including /server/load-model, /agent/stop, /session/resume, /session/search, and /account/set-nickname, which are not registered in the current daemon. HTTP endpoints live in the daemon.

Modelfile Reference

A Modelfile is a text-based blueprint for a model’s configuration, parameters, templates, and system prompt. Tiles supports a format inspired by Ollama-style instructions. The separate tilekit Rust crate exports the Modelfile parser, implemented in tilekit/src/modelfile.rs (https://github.com/tilesprivacy/tiles/blob/main/tilekit/src/modelfile.rs) using the nom parser combinator library. It parses a text-based configuration format for defining model configurations, parameters, templates, and system prompts. This page describes **what is parsed**, **what is validated**, and **what is actually used at runtime today**. ## Quick Start Minimal working Modelfile: FROM mlx-community/gpt-oss-20b-MXFP4-Q4 SYSTEM You are a concise assistant. FROM is required. Most other fields are optional. ## Supported Instructions Tiles currently parses these top-level instructions (case-insensitive): - FROM (required, exactly one) - PARAMETER (repeatable) - TEMPLATE (at most one) - SYSTEM (latest value wins) - ADAPTER (at most one) - LICENSE (at most one) - MESSAGE (repeatable) - # comments If FROM is missing, parsing fails. ## FROM FROM is parsed as a string, but runtime behavior is intentionally narrower right now. ### What works today - Hugging Face-style **model repo identifiers**, for example: - mlx-community/gpt-oss-20b-MXFP4-Q4 - mlx-community/Qwen3.5-4B-MLX-4bit ### Important nuance - Any GGUF file hosted on Hugging Face is supported through FROM. - Local file paths are not supported yet. In short: FROM supports Hugging Face model repositories, including any GGUF file hosted on Hugging Face. Local paths are not yet supported. ## SYSTEM SYSTEM sets the system/developer instruction prompt used in chat requests. - If multiple SYSTEM lines exist, the latest one replaces earlier ones. - If omitted, Tiles falls back to the default Modelfile prompt for the selected mode. This is one of the two Modelfile fields that materially affects runtime behavior today (FROM and SYSTEM). ## PARAMETER PARAMETER is parsed and validated against an allowlist. Supported keys: - num_ctx (int) - repeat_last_n (int) - repeat_penalty (float) - temperature (float) - seed (int) - stop (string) - num_predict (int) - top_k (int) - top_p (float) - min_p (float) Notes: - Unknown parameter names fail validation. - Type mismatches fail validation. - Parameters are currently parsed/stored but not fully applied in the runtime request payload yet. ## MESSAGE MESSAGE supports role + content pairs. Accepted roles: - system - user - assistant Notes: - Messages are validated and stored. - Current runtime conversation assembly does not directly consume modelfile.messages yet. ## TEMPLATE, ADAPTER, LICENSE These instructions are parsed and validated with single-value semantics: - TEMPLATE: at most one - ADAPTER: at most one - LICENSE: at most one Current status: - They are represented in the parsed Modelfile structure. - They are not currently wired into the main model execution path. ## Comments Lines beginning with # are accepted and preserved in serialized Modelfile output. ## Current Runtime Behavior In the current implementation, the Modelfile fields that directly influence execution are: 1. FROM (Hugging Face model repository identifier, including repositories containing GGUF files) 2. SYSTEM (prompt override/fallback behavior) Other parsed fields are available at parse/validation level and can be considered forward-compatible surface for future runtime expansion. ## Example FROM mlx-community/gpt-oss-20b-MXFP4-Q4 SYSTEM """ You are Tiles assistant. Keep answers practical and concise. """ PARAMETER temperature 0.2 PARAMETER num_ctx 4096 The example above is valid. Today, FROM and SYSTEM drive behavior directly; parameter validation still applies. ================================================================================ ## Community initiatives archive IndiaFOSS 2026 giveaway: Tiles Privacy and Sol PBC (https://solpbc.org/) ran an IndiaFOSS 2026 giveaway for OSDC members. Ten selected applicants received conference tickets and swag, and five also received a $100 travel grant. Poster: https://tiles.run/indiafoss-2026-giveaway.png Archived form: https://tiles.run/indiafoss-2026-giveaway Source page: https://tiles.run/book/community#community-initiatives ================================================================================ ## Book: Resources (https://tiles.run/book/resources) A living index of resources (articles, papers, talks, videos, and tools) that inform and inspire the Tiles team's work. The list can also be viewed on Semble: https://semble.so/profile/tiles.run/collections/3mkplxagc4i2q Total links: 92. Links marked as highlighted are team picks (shown with a sparkle on the page). Category: Motivations - Mitigating Geopolitical Risks with Local-First Software and atproto, Martin Kleppmann (highlighted): https://www.infoq.com/presentations/cloud-computing-technological-sovereignty-multi-cloud/ - This is Cuba's Netflix, Hulu, and Spotify – all without the internet (highlighted): https://www.youtube.com/watch?v=fTTno8D-b2E - Cuba's Underground Gaming Network: https://www.youtube.com/watch?v=lEplzHraw3c - Weathering Software Winter (highlighted): https://www.youtube.com/watch?v=9TJuOwy4aGA&t=968s - The Memory Walled Garden (highlighted): https://asimovaddendum.substack.com/p/the-memory-walled-garden - The Resonant Computing Manifesto (highlighted): https://resonantcomputing.org - Why Tech Needs Personalization (highlighted): https://om.co/2025/10/29/why-tech-needs-personalization/ - File over app (highlighted): https://stephango.com/file-over-app - Local-First Software: Taking Back Control of Our Data | a mini-doc (highlighted): https://www.youtube.com/watch?v=10d8HxS4y_g - On an Atmosphere OS, Scott (highlighted): https://scott.leaflet.pub/3mry5dbjdg22a Category: Links / LLMs - Agent Skills | Chainguard (highlighted): https://www.chainguard.dev/agent-skills - Code Mode: give agents an entire API in 1,000 tokens (highlighted): https://blog.cloudflare.com/code-mode-mcp/ - Comparative Analysis of Retrieval Systems in the Real World: https://arxiv.org/pdf/2405.02048 - The Bitter Lesson of LLM Extensions: https://www.sawyerhood.com/blog/llm-extension - Jan-nano Technical Report (highlighted): https://arxiv.org/abs/2506.22760 - Minions: the rise of small, on-device LMs: https://hazyresearch.stanford.edu/blog/2025-02-24-minions - The Bitter Lesson is coming for Tokenization (highlighted): https://lucalp.dev/bitter-lesson-tokenization-and-blt/ - Transformer²: Self-Adaptive LLMs: https://sakana.ai/transformer-squared/ - Mixture-of-Depths: Dynamically allocating compute in transformer-based language models: https://arxiv.org/abs/2404.02258 - Small Language Models are the Future of Agentic AI, NVIDIA Research (highlighted): https://arxiv.org/abs/2506.02153 - LLM in a flash: Efficient Large Language Model Inference with Limited Memory: https://arxiv.org/abs/2312.11514 - Kinetics: Rethinking Test-Time Scaling Laws: https://openreview.net/attachment?id=qxnJrm47Ag&name=pdf - Enhancing Reasoning Capabilities of Small Language Models with Blueprints and Prompt Template Search: https://openreview.net/attachment?id=LsNstclw8Z&name=pdf - FedVLM: Scalable Personalized Vision-Language Models through Federated Learning: https://arxiv.org/abs/2507.17088 - Model Merging in LLMs, MLLMs, and Beyond: Methods, Theories, Applications and Opportunities (highlighted): https://arxiv.org/abs/2408.07666 - Your LLM Knows the Future: Uncovering Its Multi-Token Prediction Potential: https://arxiv.org/abs/2507.11851 - Cephalo: Multi-Modal Vision-Language Models for Bio-Inspired Materials Analysis and Design: https://arxiv.org/abs/2405.19076 - The GPU-Poor LLM Gladiator Arena: https://huggingface.co/spaces/k-mktr/gpu-poor-llm-arena - The State of Open Models (highlighted): https://youtu.be/FUcilE5Gx_0?si=9aP_NAzTKi8qw78n - The State of On-Device LLMs (highlighted): https://app.getcontrast.io/register/sota-the-state-of-llms - r/LocalLLaMA (highlighted): https://www.reddit.com/r/LocalLLaMA/ - LLMs on a Budget (highlighted): https://benjaminmarie.gumroad.com/l/llms-on-a-budget - An Analogy for Understanding Transformers (highlighted): https://www.lesswrong.com/posts/euam65XjigaCJQkcN/an-analogy-for-understanding-transformers - Neural networks, 3Blue1Brown (highlighted): https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi - Personalized Machine Learning (highlighted): https://cseweb.ucsd.edu/~jmcauley/pml/ Category: Links / Inference - Introducing the unified multi-modal `MLX` engine architecture in LM Studio (highlighted): https://lmstudio.ai/blog/unified-mlx-engine - Pie:Programmable LLM Serving (highlighted): https://pie-project.org/ - Serve Programs, Not Prompts (highlighted): https://ingim.org/papers/gim2025serve.pdf - Pie: A Programmable Serving System for Emerging LLM Applications (highlighted): https://ingim.org/papers/gim2025pie.pdf - Intelligence Per Watt: A Study of Local Intelligence Efficiency (highlighted): https://hazyresearch.stanford.edu/blog/2025-11-11-ipw - NVIDIA eGPU on macOS: RTX 3090 & 5090 Benchmarks | lucebox (highlighted): https://www.lucebox.com/blog/egpu-myth - Equivariance Encryption for Private LLM Inference (highlighted): https://davide221.github.io/articles/equivariance-encryption.html - The Power of Efficiency: Edge AI's Role in Sustainable Generative AI Adoption (highlighted): https://creativestrategies.com/research/gen-ai-edge-testing/ - WhisperKit: On-device Real-time ASR with Billion-Scale Transformers, Argmax: https://openreview.net/attachment?id=6lC3MPFbVg&name=pdf - Towards Feasible Private Distributed LLM Inference, Dria: https://dria.co/research/towards-feasible-private-distributed-llm-inference - InferenceMAX™: Open Source Inference Benchmarking: https://newsletter.semianalysis.com/p/inferencemax-open-source-inference - Reference implementation of the Transformer architecture optimized for Apple Neural Engine: https://github.com/apple/ml-ane-transformers - Understanding AI/LLM Quantisation Through Interactive Visualisations (highlighted): https://smcleod.net/2024/07/understanding-ai/llm-quantisation-through-interactive-visualisations/ - The Kaitchup Index: A Leaderboard for Quantized LLMs (highlighted): https://kaitchup.substack.com/p/the-kaitchup-index - GGUF Quantization Docs (Unofficial): https://github.com/iuliaturc/gguf-docs - Reverse-engineering GGUF | Post-Training Quantization: https://www.youtube.com/watch?v=vW30o4U9BFE - Choosing a GGUF Model: K-Quants, I-Quants, and Legacy Formats: https://kaitchup.substack.com/p/choosing-a-gguf-model-k-quants-i Category: Links / Training - The Continual Learning Problem, Jessy Lin (highlighted): https://jessylin.com/2025/10/20/continual-learning/ - Defining Continual Learning (highlighted): https://x.com/carnot_cyclist/status/2041479655035679163 - Xet is on the Hub (highlighted): https://huggingface.co/blog/xet-on-the-hub - Ellora: Enhancing LLMs with LoRA: https://github.com/codelion/ellora_ - LoRA Without Regret (highlighted): https://thinkingmachines.ai/blog/lora/ - Pretraining with hierarchical memories: separating long-tail and common knowledge, Apple (highlighted): https://www.arxiv.org/abs/2510.02375 - LoRA Learns Less and Forgets Less: https://arxiv.org/abs/2405.09673 - Text-to-LoRA: Hypernetworks that adapt LLMs for specific benchmark tasks using only textual task description as the input, Sakana AI (highlighted): https://arxiv.org/abs/2506.06105 - Introducing FlexOlmo: a new paradigm for language model training and data collaboration, Allen AI: https://allenai.org/blog/flexolmo - Towards Large-scale Training on Apple Silicon, Exo Labs (highlighted): https://openreview.net/pdf?id=TJjP8d5bms - LoFT: Low-Rank Adaptation That Behaves Like Full Fine-Tuning: https://arxiv.org/pdf/2505.21289 - AirLLM: Diffusion Policy-based Adaptive LoRA for Remote Fine-Tuning of LLM over the Air: https://arxiv.org/abs/2507.11515 - How to Scale Your Model: https://jax-ml.github.io/scaling-book/ - RFT, DPO, SFT: Fine-tuning with OpenAI: Ilan Bigio, OpenAI: https://www.youtube.com/watch?v=JfaLQqfXqPA - Hand-picked selection of articles on AI fundamentals/concepts that cover the entire process of building neural nets to training them to evaluating results. (highlighted): https://aman.ai/primers/ai/ Category: Links / Memory - mem-agent: Equipping LLM Agents with Memory Using RL (highlighted): https://dria.co/research/mem-agent:-equipping-llm-agents-with-memory-using-rl - Memory Layers at Scale, Meta FAIR (highlighted): https://arxiv.org/abs/2412.09764 - On the Way to LLM Personalization: Learning to Remember User Conversations, Apple Machine Learning Research: https://machinelearning.apple.com/research/on-the-way - Memory OS of AI Agent: https://arxiv.org/abs/2506.06326 - Titans + MIRAS: Helping AI have long-term memory, Google Research: https://research.google/blog/titans-miras-helping-ai-have-long-term-memory/ - How memory augmentation can improve large language models, IBM Research: https://research.ibm.com/blog/memory-augmented-LLMs - On the Way to LLM Personalization: Learning to Remember User Conversations: https://arxiv.org/abs/2411.13405 - ChatGPT Memory and the Bitter Lesson (highlighted): https://www.shloked.com/writing/chatgpt-memory-bitter-lesson - Anthropic's Opinionated Memory Bet: https://shloked.com/writing/claude-memory-tool - Benchmarking Honcho: https://blog.plasticlabs.ai/research/Benchmarking-Honcho - Git Based Memory Storage for Conversational AI Agent: https://github.com/Growth-Kinetics/DiffMem Category: Links / Security - A Preliminary Report On Edge-Verified Machine Learning (evML) (highlighted): https://github.com/exo-explore/evML/blob/main/A_Preliminary_Report_On_evML.pdf - A Preliminary Report On Edge-Verified Machine Learning, Exo Labs: https://github.com/exo-explore/evML/blob/main/A_Preliminary_Report_On_evML.pdf - Defeating Prompt Injections by Design, Google Deepmind (highlighted): https://arxiv.org/abs/2503.18813 - dstack - Open Source Confidential Computing | Phala (highlighted): https://phala.com/dstack - Intent-Based Architecture and Their Risks (highlighted): https://www.paradigm.xyz/2023/06/intents - Mind the Trust Gap: Fast, Private Local-to-Cloud LLM Chat: https://hazyresearch.stanford.edu/blog/2025-05-12-security - MCP Colors: Systematically deal with prompt injection risk: https://timkellogg.me/blog/2025/11/03/colors - New physical attacks are quickly diluting secure enclave defenses from Nvidia, AMD, and Intel: https://arstechnica.com/security/2025/10/new-physical-attacks-are-quickly-diluting-secure-enclave-defenses-from-nvidia-amd-and-intel/ - User-Agent header, MDN (highlighted): https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/User-Agent Category: Links / Miscellaneous - PortableApps.com: https://en.wikipedia.org/wiki/PortableApps.com - Mosh: the mobile shell: https://mosh.org - Self-driving infrastructure (highlighted): https://vercel.com/blog/self-driving-infrastructure - OpenPoke: Recreating Poke's Architecture (highlighted): https://www.shloked.com/writing/openpoke - What happened to custom ROMs?: https://www.youtube.com/watch?v=HImV4rSps48 ================================================================================ ## Additional URLs - Privacy: https://tiles.run/privacy - Terms: https://tiles.run/terms - Refund Policy: https://tiles.run/refund-policy - Tiles Pro includes a 7-day money-back guarantee on the initial subscription payment. - Research: https://tiles.run/book/research - About: https://tiles.run/about - Sponsor: https://tiles.run/sponsor - Help: https://tiles.run/help - Press Kit: https://tiles.run/press-kit - Brand: https://tiles.run/brand - Releases: https://tiles.run/releases - Sub-processors: https://tiles.run/sub-processors - RSS: https://tiles.run/api/rss ================================================================================