Repository navigation
Expand file tree
/
Copy pathstack.example.toml
More file actions
145 lines (127 loc) · 6.74 KB
/
Copy pathstack.example.toml
File metadata and controls
145 lines (127 loc) · 6.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# stack.toml — famstack configuration
#
# Copy this to stack.toml and edit it: cp stack.example.toml stack.toml
# Or run: stack init (does this automatically)
#
# stack.toml is gitignored — your settings won't conflict with updates.
# The only value you must set is data_dir. Everything else has sensible defaults.
[core]
# Product name — used in CLI messages and UI branding.
name = "famstack"
# Leave empty for port mode (zero setup, access via hostname:port from any device).
# Set to enable pretty URLs via Caddy reverse proxy (the infra stacklet):
# domain = "home.internal" → photos.home.internal, docs.home.internal
# Needs two DNS records to the server's LAN IP, *.home.internal and
# home.internal itself: a wildcard does not cover the bare name.
domain = ""
# With a domain, HTTPS for every service: one wildcard certificate plus one
# for the bare domain, from Let's Encrypt. Caddy proves you own the domain by
# writing a DNS record through your DNS provider's API, so nothing has to be
# reachable from the internet. The domain must be one you own at the provider.
# "hetzner" or "cloudflare". Empty serves plain HTTP.
# `stack up infra` asks for the API token; `stack infra dns-token` replaces it.
dns_provider = ""
# Absolute path where all persistent data lives: databases, uploads, config.
# This directory is NOT managed by git — back it up separately.
# The ~ shorthand is expanded by the stack CLI.
data_dir = "~/famstack-data"
# Where stacklets that don't ship with famstack live: one you wrote, one
# you cloned, one that isn't finished yet. Any subdirectory with a
# stacklet.toml is discovered exactly like the built-in ones, so
# `stack up <id>` works the same.
#
# Defaults to ~/famstack-extensions, which nothing creates: make it when
# you have a stacklet to put in it. Deliberately outside both this repo
# (an upgrade replaces it) and the data dir (that is what running services
# write, not where source belongs).
#
# A list if you want more than one, searched in order, so the first entry
# wins a name clash. It is also the one mounted into the bot runner, so a
# stacklet that ships a bot belongs there.
#
# Spelled out rather than left to the default, so the path is greppable
# and does not move if you rename the stack. Add a second entry for a
# working copy: ["~/famstack-extensions", "~/dev/my-stacklets"].
extension_dirs = ["~/famstack-extensions"]
# Timezone for containers that need one (Immich, Paperless, cron jobs, etc.)
# Full list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
timezone = "UTC"
# Household language. Drives the seeded document taxonomy (Paperless tags
# and document types) and other localized strings.
# The installer auto-detects this from your timezone:
# Europe/Berlin, Europe/Vienna, Europe/Zurich → "de"
# everything else → "en"
# Supported: "en", "de" (for now).
# Change it and run: stack restart docs (re-seeds missing tags, might require a tag cleanup)
language = "en"
[updates]
# When Watchtower runs its nightly image update check.
# Format: 6-field cron (seconds minutes hours day-of-month month day-of-week)
# Default: 3am every night — quiet hours for most households.
# Set to "" to disable automatic updates entirely.
schedule = "0 0 3 * * *"
[ai]
# OpenAI-compatible API endpoint for LLM inference. Everything that uses
# AI talks to this one address. `stack up ai` installs the local engine
# and sets it. For a server on another machine or a hosted provider, run
# `./stack ai switch <url>` instead: it checks the server, picks a model
# it has and writes this section, without installing anything here.
# oMLX native app: http://localhost:8000/v1 (default)
# oMLX via brew: http://localhost:42060/v1
# LM Studio: http://localhost:42061/v1
# Containers reach localhost automatically via host.docker.internal.
openai_url = "http://localhost:8000/v1"
# API key for the local LLM server. Any value works — this is just local auth.
openai_key = "local"
# Default model for all AI tasks. Bots resolve models by path:
# resolve("archivist/classifier") walks:
# 1. [ai.models] archivist.classifier — task-specific override
# 2. [ai.models] archivist — bot-level override
# 3. [ai] default — fallback for everything
# Required when running bots. Set to whatever model you have loaded.
#
# Recommended defaults by RAM:
# 32GB: mlx-community/Qwen3.5-9B-MLX-8bit
# 64GB: mlx-community/Qwen2.5-14B-Instruct-4bit
# TODO: model profiles (8GB, 16GB, 32GB, 64GB) coming soon
default = "mlx-community/Qwen3.5-9B-MLX-8bit"
# Override models per bot or per task. Bots resolve by path:
# resolve("archivist/classifier") checks in order:
# archivist.classifier → archivist → default (above)
#
# Examples:
# [ai.models]
# archivist = "mlx-community/Qwen2.5-14B-Instruct-4bit" # all archivist tasks use this
# archivist.classifier = "mlx-community/Qwen2.5-7B-Instruct-4bit" # fast model just for classification
# Speech-to-text for voice messages, a dedicated server that answers
# the OpenAI transcription API. `stack up ai` sets it to the local
# Whisper, built from source because the Homebrew formula disables the
# HTTP server. Left unset, voice messages go to openai_url above, which
# then needs a speech-to-text model loaded.
whisper_url = "http://localhost:42062/v1"
# whisper_key = "" # only for a speech server that needs one
# whisper_model = "whisper-1" # the speech model to ask the server for
# The language the stack speaks to you: the voice that reads answers
# aloud. Can differ from [core] language, which decides transcription.
# "en" = English (alloy voice), "de" = German (onyx voice)
language = "en"
[backup]
# Nightly append-only backup of stacklet data. Enable the backup stacklet
# (`stack up backup`) to install the cron entry that runs the sync and to
# grant Full Disk Access to /usr/sbin/cron. Each [[backup.targets.*]] block
# defines one destination; sources are discovered from stacklets that
# declare [[backup.archive]] (append-only) in their own manifest.
#
# In v1 only the external-disk engine ships. Restic-based encrypted
# offsite is planned and will slot in as a second target without
# touching this file's existing entries.
# [backup.targets.vault]
# engine = "external-disk" # rsync + chflags uchg + diskutil eject
# disk = "backup-vault" # APFS volume name (case-sensitive)
# schedule = "0 2 * * *" # 5-field cron, runs nightly at 02:00
[services]
# Homepage dashboard URL — set automatically when core is enabled.
homepage_url = "http://localhost:3000"
# Host service API — only needed when the stack CLI itself runs inside a
# container (e.g. as an OpenClaw agent). Leave unset for native macOS installs.
# host_service = "http://host.docker.internal:6110"