A local-first private AI assistant for everyday use. Runs on-device models with encrypted P2P sync, and supports sharing chats publicly on ATProto.
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Added scripts and just command for .pkg build - just build_pkg for building .pkg

madclaws 72b84a77 ef9f7168

+135 -39
+2
.gitignore
··· 6 6 tilekit/target 7 7 tiles/target 8 8 .DS_Store 9 + pkgroot/ 10 + *.pkg
+1 -1
Cargo.lock
··· 4255 4255 4256 4256 [[package]] 4257 4257 name = "tiles" 4258 - version = "0.4.2" 4258 + version = "0.4.3" 4259 4259 dependencies = [ 4260 4260 "anyhow", 4261 4261 "async-std",
+3
justfile
··· 20 20 21 21 install: 22 22 ./scripts/install.sh 23 + 24 + bundle_pkg: 25 + ./pkg/build.sh
+73
pkg/build.sh
··· 1 + #!/usr/bin/env bash 2 + 3 + set -euo pipefail 4 + 5 + VERSION=$(grep '^version' tiles/Cargo.toml | head -1 | awk -F'"' '{print $2}') 6 + 7 + TARGET="release" 8 + MODELFILE_DIR="modelfiles" 9 + SERVER_DIR="server" 10 + BINARY_NAME="tiles" 11 + 12 + VERSION=$(grep '^version' tiles/Cargo.toml | head -1 | awk -F'"' '{print $2}') 13 + OS=$(uname -s | tr '[:upper:]' '[:lower:]') 14 + ARCH=$(uname -m) 15 + OUT_NAME="${BINARY_NAME}-v${VERSION}-${ARCH}-${OS}" 16 + 17 + echo "🚀 Building ${BINARY_NAME} (${TARGET} mode)..." 18 + 19 + cargo build -p tiles --${TARGET} 20 + 21 + CLI_BIN_PATH="pkgroot/usr/local/bin" 22 + LIBS_PATH="pkgroot/usr/local/share/tiles" 23 + 24 + # CLI binary install path 25 + 26 + mkdir -p "${CLI_BIN_PATH}" 27 + 28 + mkdir -p "${LIBS_PATH}" 29 + 30 + 31 + # move cli to bin path 32 + 33 + cp "target/${TARGET}/${BINARY_NAME}" "${CLI_BIN_PATH}" 34 + chmod +x "${CLI_BIN_PATH}/tiles" 35 + 36 + 37 + # Build venvstack and move to /usr/local/share/tiles 38 + # 39 + # flushing this folder, else the final zip will have previous app-server zips too (#84) 40 + 41 + rm -rf "${SERVER_DIR}/stack_export_prod" 42 + 43 + echo "🔒 Locking the venvstack...." 44 + 45 + venvstacks lock server/stack/venvstacks.toml 46 + 47 + echo "🛠️ Building the venvstack...." 48 + 49 + venvstacks build server/stack/venvstacks.toml 50 + 51 + echo "📦 Publishing the venvstack...." 52 + 53 + venvstacks publish --tag-outputs --output-dir ../stack_export_prod server/stack/venvstacks.toml 54 + 55 + cp -r "${SERVER_DIR}" "${LIBS_PATH}" 56 + 57 + rm -rf "${LIBS_PATH}/server/__pycache__" 58 + rm -rf "${LIBS_PATH}/server/mem_agent/__pycache__" 59 + rm -rf "${LIBS_PATH}/server/backend/__pycache__" 60 + rm -rf "${LIBS_PATH}/server/.venv" 61 + rm -rf "${LIBS_PATH}/server/stack" 62 + 63 + cp -r "${MODELFILE_DIR}" "${LIBS_PATH}" 64 + 65 + 66 + # Creating .pkg 67 + pkgbuild --root pkgroot --scripts pkg/scripts --identifier com.tilesprivacy.tiles --version "$VERSION" "tiles-${VERSION}".pkg" 68 + 69 + 70 + # signing 71 + 72 + 73 + # notarizing
+17
pkg/scripts/postinstall
··· 1 + #!/bin/bash 2 + 3 + SERVER_DIR="/usr/local/share/tiles/server" 4 + 5 + echo "🔧 Setting up Python environment..." 6 + 7 + cd "${SERVER_DIR}/stack_export_prod" || exit 1 8 + 9 + for f in *.tar.xz; do 10 + tar -xvf "$f" 11 + done 12 + 13 + rm -f *.tar.xz 14 + 15 + ./cpython3.13/bin/python cpython3.13/postinstall.py 16 + ./framework-mlx/bin/python framework-mlx/postinstall.py 17 + ./app-server/bin/python app-server/postinstall.py
+9 -4
scripts/install.sh
··· 4 4 ENV="prod" # prod is another env, try taking it from github env 5 5 REPO="tilesprivacy/tiles" 6 6 # VERSION="${TILES_VERSION:-latest}" 7 - VERSION="0.4.2" 8 - INSTALL_DIR="$HOME/.local/bin" # CLI install location 9 - SERVER_DIR="$HOME/.local/lib/tiles/server" # Python server folder 10 - MODELFILE_DIR="$HOME/.local/lib/tiles/modelfiles" # Python server folder 7 + VERSION="0.4.3" 8 + # INSTALL_DIR="$HOME/.local/bin" # CLI install location 9 + INSTALL_DIR="/usr/local/bin" # CLI install location 10 + # SERVER_DIR="$HOME/.local/lib/tiles/server" # Python server folder 11 + # MODELFILE_DIR="$HOME/.local/lib/tiles/modelfiles" # Python server folder 12 + 13 + SERVER_DIR="/usr/local/share/tiles/server" # Python server folder 14 + MODELFILE_DIR="/usr/local/share/tiles/modelfiles" # Python server folder 15 + 11 16 TMPDIR="$(mktemp -d)" 12 17 OS=$(uname -s | tr '[:upper:]' '[:lower:]') 13 18 ARCH=$(uname -m)
+2 -2
server/stack/requirements/app-server/packages-app-server.txt
··· 4 4 anyio==4.12.1 5 5 black==25.9.0 6 6 certifi==2026.2.25 7 - charset-normalizer==3.4.4 7 + charset-normalizer==3.4.5 8 8 click==8.3.1 9 9 fastapi==0.119.0 10 10 filelock==3.25.0 ··· 22 22 openresponses-types==2.3.0.post1 23 23 packaging==26.0 24 24 pathspec==1.0.4 25 - platformdirs==4.9.2 25 + platformdirs==4.9.4 26 26 protobuf==7.34.0 27 27 pydantic==2.12.5 28 28 pydantic-core==2.41.5
+2 -2
server/stack/requirements/app-server/pylock.app-server.meta.json
··· 1 1 { 2 2 "lock_input_hash": "sha256:c836d5cfb697330a57241b2b8f275a804178488ec906b19866809ef33c95ba81", 3 3 "lock_version": 1, 4 - "locked_at": "2026-03-01T18:20:47.939345+00:00", 4 + "locked_at": "2026-03-08T15:32:49.822954+00:00", 5 5 "other_inputs_hash": "sha256:63b3c2cfe2ec414938e81dace7aac779c7b902bae681618cd8827e9f16880985", 6 - "requirements_hash": "sha256:bc1a0df3c15a1fad6f446be81a50a01835c1a11ff412440842f751ecdce9cbdd", 6 + "requirements_hash": "sha256:579ae09437373494896b65ca902382b680f2d42170dfa57c62618ca7d5d3457a", 7 7 "version_inputs_hash": "sha256:58db986b7cd72eeded675f7c9afd8138fe024fb51451131b5562922bbde3cf43" 8 8 }
+22 -22
server/stack/requirements/app-server/pylock.app-server.toml
··· 75 75 76 76 [[packages]] 77 77 name = "charset-normalizer" 78 - version = "3.4.4" 78 + version = "3.4.5" 79 79 index = "https://pypi.org/simple" 80 80 81 81 [[packages.wheels]] 82 - url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl" 83 - upload-time = 2025-10-14T04:41:13Z 84 - size = 208091 82 + url = "https://files.pythonhosted.org/packages/f5/48/9f34ec4bb24aa3fdba1890c1bddb97c8a4be1bd84ef5c42ac2352563ad05/charset_normalizer-3.4.5-cp313-cp313-macosx_10_13_universal2.whl" 83 + upload-time = 2026-03-06T06:01:37Z 84 + size = 280788 85 85 86 86 [packages.wheels.hashes] 87 - sha256 = "e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794" 87 + sha256 = "ac59c15e3f1465f722607800c68713f9fbc2f672b9eb649fe831da4019ae9b23" 88 88 89 89 [[packages.wheels]] 90 - url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" 91 - upload-time = 2025-10-14T04:41:19Z 92 - size = 153076 90 + url = "https://files.pythonhosted.org/packages/94/0a/af49691938dfe175d71b8a929bd7e4ace2809c0c5134e28bc535660d5262/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" 91 + upload-time = 2026-03-06T06:01:43Z 92 + size = 195572 93 93 94 94 [packages.wheels.hashes] 95 - sha256 = "a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894" 95 + sha256 = "0625665e4ebdddb553ab185de5db7054393af8879fb0c87bd5690d14379d6819" 96 96 97 97 [[packages.wheels]] 98 - url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl" 99 - upload-time = 2025-10-14T04:41:28Z 100 - size = 154465 98 + url = "https://files.pythonhosted.org/packages/84/31/faa6c5b9d3688715e1ed1bb9d124c384fe2fc1633a409e503ffe1c6398c1/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_x86_64.whl" 99 + upload-time = 2026-03-06T06:01:56Z 100 + size = 197509 101 101 102 102 [packages.wheels.hashes] 103 - sha256 = "9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc" 103 + sha256 = "c7a80a9242963416bd81f99349d5f3fce1843c303bd404f204918b6d75a75fd6" 104 104 105 105 [[packages.wheels]] 106 - url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl" 107 - upload-time = 2025-10-14T04:42:31Z 108 - size = 53402 106 + url = "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl" 107 + upload-time = 2026-03-06T06:03:17Z 108 + size = 55455 109 109 110 110 [packages.wheels.hashes] 111 - sha256 = "7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f" 111 + sha256 = "9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0" 112 112 113 113 [[packages]] 114 114 name = "click" ··· 495 495 496 496 [[packages]] 497 497 name = "platformdirs" 498 - version = "4.9.2" 498 + version = "4.9.4" 499 499 index = "https://pypi.org/simple" 500 500 501 501 [[packages.wheels]] 502 - url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl" 503 - upload-time = 2026-02-16T03:56:08Z 504 - size = 21168 502 + url = "https://files.pythonhosted.org/packages/63/d7/97f7e3a6abb67d8080dd406fd4df842c2be0efaf712d1c899c32a075027c/platformdirs-4.9.4-py3-none-any.whl" 503 + upload-time = 2026-03-05T18:34:12Z 504 + size = 21216 505 505 506 506 [packages.wheels.hashes] 507 - sha256 = "9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd" 507 + sha256 = "68a9a4619a666ea6439f2ff250c12a853cd1cbd5158d258bd824a7df6be2f868" 508 508 509 509 [[packages]] 510 510 name = "protobuf"
+1 -1
tiles/Cargo.toml
··· 1 1 [package] 2 2 name = "tiles" 3 - version = "0.4.2" 3 + version = "0.4.3" 4 4 edition = "2024" 5 5 6 6 [dependencies]
+1 -4
tiles/src/runtime/mlx.rs
··· 455 455 .from 456 456 .clone() 457 457 .ok_or_else(|| anyhow!("Failed to get model name"))?; 458 - let prompt = modelfile 459 - .system 460 - .clone() 461 - .ok_or_else(|| anyhow!("Failed to get system prompt"))?; 458 + let prompt = modelfile.system.clone().unwrap_or("".to_owned()); 462 459 let convo_input = create_chat_input(input, prompt.as_str(), conversations); 463 460 let body = json!({ 464 461 "model": modelname,
+2 -3
tiles/src/utils/config.rs
··· 9 9 /// - /logs 10 10 /// - /data (default, user can change this location tho) 11 11 /// - /memory (memory stored as PKM) 12 - /// - ~/.local/lib/tiles (lib dir) - Some internal App files, libraries etc go here.. 12 + /// - /usr/local/share/tiles (lib dir) - Some internal App files, libraries etc go here.. 13 13 /// - /modelfiles 14 14 /// - /server 15 15 use anyhow::{Context, Result, anyhow}; ··· 117 117 let base_dir = env::current_dir().context("Failed to fetch CURRENT_DIR")?; 118 118 Ok(base_dir) 119 119 } else { 120 - let home_dir = env::home_dir().context("Failed to fetch $HOME")?; 121 - let data_dir = home_dir.join(".local/lib"); 120 + let data_dir = PathBuf::from_str("/usr/local/share")?; 122 121 Ok(data_dir.join("tiles")) 123 122 } 124 123 }