Squire is a self-hosted personal organizer you talk to through Discord. You send quick notes in a DM, and Squire turns them into structured notes you can review, search, and update later.
- Captures notes from Discord DMs
- Organizes notes into four groups: tasks, projects, people, and ideas
- Sends daily and weekly review messages
- Supports configurable pre-due reminders for timed admin items (
due_at) - Lets you search and inspect notes with simple commands
- Allows you to make updates and edits to notes using natural language
- Uses conservative matching and confirmation gates to reduce accidental edits
- Stores your data on your own machine
For surfacing details (daily digest, weekly review, due-time reminders), see docs/surfacing.md.
You send a message to your Squire Discord bot, and Squire saves the original message first. It then uses AI to extract useful fields (title, status, due date, and similar details), writes the result as readable Markdown files in your archive folder, and updates a local SQLite index so search commands stay fast. For update/append decisions, Squire ranks likely matches with hybrid lexical + semantic retrieval and applies deterministic safety gates before mutating existing notes.
Core commands:
!status- show daily review now!weekly- show weekly review now!recent [number] [category]- list recent notes!active [number] [category]- list active notes grouped by type!find <query>- search notes!show <number>- open one result from your latest numbered list!detail <number>- show the full note object for one result from your latest numbered list!help [command]- show available commands or detailed help for one command!append <id|number> <text>- add text to a note (<number>uses your latest numbered list)!done <id|number>- mark a note as done (<number>uses your latest numbered list)!reopen <id|number>- reopen a done note (<number>uses your latest numbered list)!fix <id|number> [field=value ...]- show or edit note fields (<number>uses your latest numbered list)!confirm <pending_id>/!cancel <pending_id>- approve or cancel a suggested change!clear-archivethenDELETE- clear archive data (keeps.git)
Optional prefixes when capturing:
admin:(tasks/commitments)project:person:idea:
For complete command semantics, see docs/commands.md.
- Docker and Docker Compose
- A Discord bot token
OPENAI_API_KEY
cp config.yaml.example config.yamlFor containerized runs, use:
archive_root: "/data/archive"DISCORD_TOKEN=...
OPENAI_API_KEY=...docker compose up -d --builddocker compose logs -f squire-coreData mounts used by compose:
./config.yaml->/app/config.yaml(read-only)./config/->/app/config/(read-only)./archive/->/data/archive/(your data)
Squire exposes a lightweight liveness endpoint:
- Route:
GET /health - Default bind:
0.0.0.0(override withHEALTH_HOST) - Default port:
8080(override withHEALTH_PORT; setHEALTH_PORT=0to disable) - Response: HTTP
200with{"status":"ok"}
Quick check:
curl http://<host>:<health-port>/healthYou can point any HTTP-capable monitoring tool at this endpoint.
Typical checks should expect status 200 and treat any non-200 response (or connection failure) as unhealthy.
Common target examples:
- Repo default (
docker-compose.yml):http://squire-core:8080/health - Same Docker network:
http://<container-name>:<health-port>/health - From another machine/network:
http://<host-ip-or-dns>:<health-port>/health
Squire can also emit OpenTelemetry traces for user-triggered Discord flows when OTLP export is configured. There is no config.yaml tracing block; tracing is controlled entirely with standard OTEL_* environment variables.
Common tracing env vars:
OTEL_EXPORTER_OTLP_TRACES_ENDPOINTorOTEL_EXPORTER_OTLP_ENDPOINTOTEL_EXPORTER_OTLP_HEADERSOTEL_EXPORTER_OTLP_PROTOCOLOTEL_SERVICE_NAME(defaults tosquire-core)OTEL_RESOURCE_ATTRIBUTESOTEL_SDK_DISABLED=trueto force tracing off
For deployment/runtime behavior, see docs/deployment.md.
Runtime logs are split by severity:
INFO/WARNINGand below are emitted tostdoutERRORand above are emitted tostderr
- Python 3.11+
- A Discord bot token
OPENAI_API_KEY
python3 -m venv .venv
source .venv/bin/activatepip install -e .Install test/dev tools if needed:
pip install -e ".[dev]"cp config.yaml.example config.yamlSet .env:
DISCORD_TOKEN=...
OPENAI_API_KEY=...make initmake run-botFor deterministic smoke testing with a fresh seeded dataset on every startup:
make run-bot-testThis mode is destructive for the active test archive. Set test_archive_root in config.yaml (for example /tmp/squire-test-archive) to keep it separate from your normal archive_root.
Open a DM with your bot and send a simple note like Call dentist next Tuesday.
Then run !status to see your current daily view, and try !find dentist followed by !show 1 to open a matching result.
Main config file: config.yaml
Common settings include AI model/prompt paths, data storage location (archive_root), daily and weekly schedule times, and search/result display limits.
Matching defaults also include hybrid lexical + semantic retrieval for safer update/append routing.
To disable semantic scoring and run lexical-only matching, set matching.semantic_weight: 0.
For full configuration reference, see docs/configuration.md.
Start with:
config.yaml.example
make testIf pytest is missing:
pip install -e ".[dev]"This repo publishes Docker images from GitHub Actions when you push a SemVer tag (vX.Y.Z).
Example:
git tag v0.1.2
git push origin v0.1.2On your host, update containers explicitly:
docker compose pull
docker compose up -d