Files
baibot-withmcp/justfile
Slavi Pantaleev 1f2c65d2e6 Refactor dev services to support homeserver choice (Continuwuity or Synapse)
The dev environment previously hardcoded Synapse (bundled with Postgres
and Element Web) in a monolithic etc/services/core/ directory.

With Continuwuity now available as a lighter alternative (no external DB),
this refactors the service layout so developers choose their homeserver
once and everything derives from that choice. Continuwuity is the new
default for its smaller footprint.

Key changes:
- Break etc/services/core/ into etc/services/synapse/ and
  etc/services/element-web/, each with their own compose.yml
- Add `homeserver` variable in justfile (reads var/homeserver,
  defaults to continuwuity)
- Add `homeserver-init` recipe to persist the choice
- Use placeholders (__HOMESERVER_SERVER_NAME__, __HOMESERVER_URL__,
  __HOMESERVER_CLIENT_URL__) in config templates, resolved at
  prepare time based on the chosen homeserver
- Make services-start/stop/prepare/tail-logs delegate to the chosen
  homeserver's recipes + element-web
- Make users-prepare delegate to {homeserver}-users-prepare
- Update docs/development.md for the new homeserver choice flow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 05:28:32 +02:00

420 lines
15 KiB
Makefile

project_name := "baibot"
container_image_name := "localhost/baibot"
project_container_network := "baibot"
admin_username := "admin"
admin_password := "admin"
bot_username := "baibot"
bot_password := "baibot"
homeserver := `cat var/homeserver 2>/dev/null || echo continuwuity`
mise_data_dir := env("MISE_DATA_DIR", justfile_directory() / "var/mise")
mise_trusted_config_paths := justfile_directory() / "mise.toml"
# Show help by default
default:
@just --list --justfile {{ justfile() }}
# Selects which homeserver implementation to use (continuwuity or synapse)
homeserver-init value:
#!/bin/sh
mkdir -p {{ justfile_directory() }}/var
echo {{ value }} > {{ justfile_directory() }}/var/homeserver
echo ""
echo "⚠️ If you had already prepared your app configuration (var/app/local/config.yml or var/app/container/config.yml),"
echo " you will need to update it manually or delete it and re-run the prepare step."
echo " You should also delete var/app/local/data and/or var/app/container/data,"
echo " as old application state is not compatible across homeserver implementations."
echo ""
echo "⚠️ If Element Web was already prepared, delete var/services/element-web/ to regenerate its config."
# Builds and runs a development binary
run-locally *extra_args: app-local-prepare
RUST_BACKTRACE=1 \
BAIBOT_CONFIG_FILE_PATH={{ justfile_directory() }}/var/app/local/config.yml \
BAIBOT_PERSISTENCE_DATA_DIR_PATH={{ justfile_directory() }}/var/app/local/data \
cargo run -- {{ extra_args }}
# Builds and runs the bot in a container
run-in-container *extra_args: app-container-prepare build-container-image-debug
/usr/bin/env docker run \
-it \
--rm \
--name={{ project_name }} \
--user=$(id -u):$(id -g) \
--cap-drop=ALL \
--read-only \
--network={{ project_container_network }} \
--env BAIBOT_PERSISTENCE_DATA_DIR_PATH=/data \
--mount type=bind,src={{ justfile_directory() }}/var/app/container/config.yml,dst=/app/config.yml,ro \
--mount type=bind,src={{ justfile_directory() }}/var/app/container/data,dst=/data \
{{ container_image_name }}:latest {{ extra_args }}
# Runs tests
test *extra_args:
RUST_BACKTRACE=1 cargo test {{ extra_args }}
# Formats the code
fmt:
RUST_BACKTRACE=1 cargo fmt --all
# Builds a debug binary (target/debug/*)
build-debug *extra_args:
RUST_BACKTRACE=1 cargo build {{ extra_args }}
# Builds an optimized release binary (target/release/*)
build-release *extra_args: (build-debug "--release")
# Builds a container image (debug mode)
build-container-image-debug tag='latest': (_build-container-image "false" tag)
# Builds a container image (release mode)
build-container-image-release tag='latest': (_build-container-image "true" tag)
_build-container-image release_build tag:
/usr/bin/env docker build \
--build-arg RELEASE_BUILD={{ release_build }} \
-f {{ justfile_directory() }}/Dockerfile \
-t {{ container_image_name }}:{{ tag }} \
.
# Runs a docker-compose command
docker-compose services_type *extra_args:
/usr/bin/docker compose \
--project-directory var/services \
--env-file var/services/env \
-f etc/services/{{ services_type }}/compose.yml \
-p {{ project_name }}-{{ services_type }} \
{{ extra_args }}
# Runs a docker-compose command against the synapse services
docker-compose-synapse *extra_args:
just docker-compose synapse {{ extra_args }}
# Runs a docker-compose command against the element-web services
docker-compose-element-web *extra_args:
just docker-compose element-web {{ extra_args }}
# Runs a docker-compose command against the localai services
docker-compose-localai *extra_args:
just docker-compose localai {{ extra_args }}
# Runs a docker-compose command against the ollama services
docker-compose-ollama *extra_args:
just docker-compose ollama {{ extra_args }}
# Runs a docker-compose command against the continuwuity services
docker-compose-continuwuity *extra_args:
just docker-compose continuwuity {{ extra_args }}
# Runs the homeserver and Element Web (in the background)
services-start: services-prepare
just -f {{ justfile_directory() }}/justfile {{ homeserver }}-start
just -f {{ justfile_directory() }}/justfile element-web-start
# Stops Element Web and the homeserver
services-stop:
just -f {{ justfile_directory() }}/justfile element-web-stop
just -f {{ justfile_directory() }}/justfile {{ homeserver }}-stop
# Tails the logs for the homeserver and Element Web
services-tail-logs:
just -f {{ justfile_directory() }}/justfile {{ homeserver }}-tail-logs
# Prepares the homeserver and Element Web for running
services-prepare:
just -f {{ justfile_directory() }}/justfile {{ homeserver }}-prepare
just -f {{ justfile_directory() }}/justfile element-web-prepare
# Runs Synapse (in the background)
synapse-start: synapse-prepare (docker-compose-synapse "up" "-d")
# Stops Synapse
synapse-stop: (docker-compose-synapse "down")
# Tails the logs for Synapse
synapse-tail-logs: (docker-compose-synapse "logs" "-f")
# Prepares Synapse for running
synapse-prepare: _prepare-var-services-env _prepare-var-services-postgres _prepare-var-services-synapse _prepare-container-network
# Runs Element Web (in the background)
element-web-start: element-web-prepare (docker-compose-element-web "up" "-d")
# Stops Element Web
element-web-stop: (docker-compose-element-web "down")
# Tails the logs for Element Web
element-web-tail-logs: (docker-compose-element-web "logs" "-f")
# Prepares Element Web for running
element-web-prepare: _prepare-var-services-env _prepare-var-services-element-web _prepare-container-network
# Runs LocalAI (in the background)
localai-start: localai-prepare (docker-compose-localai "up" "-d")
# Stops LocalAI
localai-stop: (docker-compose-localai "down")
# Tails the logs for LocalAI
localai-tail-logs: (docker-compose-localai "logs" "-f")
# Prepares LocalAI for running
localai-prepare: _prepare-var-services-env _prepare-var-services-localai _prepare-container-network
# Runs Ollama (in the background)
ollama-start: ollama-prepare (docker-compose-ollama "up" "-d")
# Stops Ollama
ollama-stop: (docker-compose-ollama "down")
# Tails the logs for Ollama
ollama-tail-logs: (docker-compose-ollama "logs" "-f")
# Prepares Ollama for running
ollama-prepare: _prepare-var-services-env _prepare-var-services-ollama _prepare-container-network
# Runs Continuwuity (in the background)
continuwuity-start: continuwuity-prepare (docker-compose-continuwuity "up" "-d")
# Stops Continuwuity
continuwuity-stop: (docker-compose-continuwuity "down")
# Tails the logs for Continuwuity
continuwuity-tail-logs: (docker-compose-continuwuity "logs" "-f")
# Prepares Continuwuity for running
continuwuity-prepare: _prepare-var-services-env _prepare-var-services-continuwuity _prepare-container-network
# Registers a user on Continuwuity via the Matrix Client-Server API
continuwuity-register-user username password:
{{ justfile_directory() }}/etc/services/continuwuity/register-user.sh {{ justfile_directory() }}/var/services/env {{ username }} {{ password }}
# Prepares the Continuwuity user accounts
continuwuity-users-prepare: continuwuity-prepare
just -f {{ justfile_directory() }}/justfile continuwuity-register-user "{{ admin_username }}" "{{ admin_password }}"
just -f {{ justfile_directory() }}/justfile continuwuity-register-user "{{ bot_username }}" "{{ bot_password }}"
# Pulls an Ollama model
ollama-pull-model model_id:
just -f {{ justfile_directory() }}/justfile docker-compose-ollama \
exec ollama \
ollama pull {{ model_id }}
# Prepares the app for running locally
app-local-prepare: _prepare-var-app-local-config_yml _prepare-var-app-local-data
# Prepares the app for running in a container
app-container-prepare: _prepare-var-app-container-config_yml _prepare-var-app-container-data
# Prepares the user accounts
users-prepare:
just -f {{ justfile_directory() }}/justfile {{ homeserver }}-users-prepare
# Prepares the Synapse user accounts
synapse-users-prepare: synapse-prepare
just -f {{ justfile_directory() }}/justfile synapse-register-admin-user "{{ admin_username }}" "{{ admin_password }}"
just -f {{ justfile_directory() }}/justfile synapse-register-regular-user "{{ bot_username }}" "{{ bot_password }}"
# Starts a Postgres CLI (psql)
postgres-cli: synapse-prepare (docker-compose-synapse "exec" "postgres" "/bin/sh" "-c" "'PGUSER=synapse PGPASSWORD=synapse-password PGDATABASE=homeserver psql -h postgres'")
# Creates an administrator user on Synapse
synapse-register-admin-user username password: synapse-prepare
just -f {{ justfile_directory() }}/justfile docker-compose-synapse \
exec synapse \
register_new_matrix_user \
--admin \
-u {{ username }} \
-p {{ password }} \
-c /config/homeserver.yaml \
http://localhost:8008
# Creates a regular user on Synapse
synapse-register-regular-user username password: synapse-prepare
just -f {{ justfile_directory() }}/justfile docker-compose-synapse \
exec synapse \
register_new_matrix_user \
--no-admin \
-u {{ username }} \
-p {{ password }} \
-c /config/homeserver.yaml \
http://localhost:8008
# Runs the clippy linter
clippy *extra_args:
cargo clippy {{ extra_args }}
# Checks that the code compiles without building
check:
cargo check
# Invokes mise with the project-local data directory
mise *args: _ensure_mise_data_directory
#!/bin/sh
export MISE_DATA_DIR="{{ mise_data_dir }}"
export MISE_TRUSTED_CONFIG_PATHS="{{ mise_trusted_config_paths }}"
mise {{ args }}
# Runs prek (pre-commit hooks manager) with the given arguments
prek *args: _ensure_mise_tools_installed
@just --justfile {{ justfile() }} mise exec -- prek {{ args }}
# Runs pre-commit hooks on staged files
prek-run-on-staged *args: _ensure_mise_tools_installed
@just --justfile {{ justfile() }} mise exec -- prek run {{ args }}
# Runs pre-commit hooks on all files
prek-run-on-all *args: _ensure_mise_tools_installed
@just --justfile {{ justfile() }} mise exec -- prek run --all-files {{ args }}
# Installs the git pre-commit hook (runs prek automatically before each commit)
prek-install-git-pre-commit-hook: _ensure_mise_tools_installed
@just --justfile {{ justfile() }} mise exec -- prek install
# Internal - ensures var/mise directory exists
_ensure_mise_data_directory:
#!/bin/sh
if [ ! -d "{{ mise_data_dir }}" ]; then
mkdir -p "{{ mise_data_dir }}"
fi
# Internal - ensures mise tools are installed
_ensure_mise_tools_installed: _ensure_mise_data_directory
@just --justfile {{ justfile() }} mise install --quiet
_prepare-var-services-env:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/services/env ]; then
mkdir -p var/services
cp {{ justfile_directory() }}/etc/services/env.dist var/services/env
echo 'UID='`id -u` >> var/services/env;
echo 'GID='`id -g` >> var/services/env;
echo 'NETWORK_NAME={{ project_container_network }}' >> var/services/env;
fi
_prepare-var-services-postgres:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/services/postgres ]; then
mkdir -p var/services/postgres
chown `id -u`:`id -g` var/services/postgres
fi
_prepare-var-services-synapse:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/services/synapse ]; then
mkdir -p var/services/synapse/media-store
fi
_prepare-var-services-element-web:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/services/element-web/config.json ]; then
mkdir -p var/services/element-web
cp {{ justfile_directory() }}/etc/services/element-web/config.json.dist var/services/element-web/config.json
homeserver="{{ homeserver }}"
if [ "$homeserver" = "continuwuity" ]; then
sed --in-place 's|__HOMESERVER_CLIENT_URL__|http://continuwuity.127.0.0.1.nip.io:42030|g' var/services/element-web/config.json
elif [ "$homeserver" = "synapse" ]; then
sed --in-place 's|__HOMESERVER_CLIENT_URL__|http://synapse.127.0.0.1.nip.io:42020|g' var/services/element-web/config.json
fi
fi
_prepare-var-services-ollama:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/services/ollama ]; then
mkdir -p var/services/ollama
fi
_prepare-var-services-continuwuity:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/services/continuwuity ]; then
mkdir -p var/services/continuwuity/data
fi
_prepare-var-services-localai:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/services/localai ]; then
mkdir -p var/services/localai
fi
_prepare-container-network:
#!/bin/sh
network_definition=$(/usr/bin/env docker network ls --filter='name={{ project_container_network }}' --format=json)
if [ "$network_definition" = "" ]; then
/usr/bin/docker network create {{ project_container_network }}
fi
_prepare-var-app-local-config_yml:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/app/local/config.yml ]; then
mkdir -p var/app/local
cp {{ justfile_directory() }}/etc/app/config.yml.dist var/app/local/config.yml
homeserver="{{ homeserver }}"
if [ "$homeserver" = "continuwuity" ]; then
sed --in-place 's/__HOMESERVER_SERVER_NAME__/continuwuity.127.0.0.1.nip.io/g' var/app/local/config.yml
sed --in-place 's|__HOMESERVER_URL__|http://continuwuity.127.0.0.1.nip.io:42030|g' var/app/local/config.yml
elif [ "$homeserver" = "synapse" ]; then
sed --in-place 's/__HOMESERVER_SERVER_NAME__/synapse.127.0.0.1.nip.io/g' var/app/local/config.yml
sed --in-place 's|__HOMESERVER_URL__|http://synapse.127.0.0.1.nip.io:42020|g' var/app/local/config.yml
fi
fi
_prepare-var-app-local-data:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/app/local/data ]; then
mkdir -p var/app/local/data
fi
_prepare-var-app-container-config_yml:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/app/container/config.yml ]; then
mkdir -p var/app/container
cp {{ justfile_directory() }}/etc/app/config.yml.dist var/app/container/config.yml
homeserver="{{ homeserver }}"
if [ "$homeserver" = "continuwuity" ]; then
sed --in-place 's/__HOMESERVER_SERVER_NAME__/continuwuity.127.0.0.1.nip.io/g' var/app/container/config.yml
sed --in-place 's|__HOMESERVER_URL__|http://continuwuity.127.0.0.1.nip.io:42030|g' var/app/container/config.yml
sed --in-place 's/continuwuity.127.0.0.1.nip.io:42030/continuwuity:6167/g' var/app/container/config.yml
elif [ "$homeserver" = "synapse" ]; then
sed --in-place 's/__HOMESERVER_SERVER_NAME__/synapse.127.0.0.1.nip.io/g' var/app/container/config.yml
sed --in-place 's|__HOMESERVER_URL__|http://synapse.127.0.0.1.nip.io:42020|g' var/app/container/config.yml
sed --in-place 's/synapse.127.0.0.1.nip.io:42020/synapse:8008/g' var/app/container/config.yml
fi
sed --in-place 's/127.0.0.1:42026/ollama:11434/g' var/app/container/config.yml
sed --in-place 's/127.0.0.1:42027/localai:8080/g' var/app/container/config.yml
fi
_prepare-var-app-container-data:
#!/bin/sh
cd {{ justfile_directory() }};
if [ ! -f var/app/container/data ]; then
mkdir -p var/app/container/data
fi