Friday Chat client quick start
This guide takes you from installation to a repeatable Friday Chat session, with your own runtime, model and terminal configuration. Choose one installation path, then follow the shared configuration steps:
| Use case | Starting point | Installation path |
|---|---|---|
| UC1 | You cloned this repository and want the complete local workspace | Install from a clone |
| UC2 | You want the published framework in an existing Python environment/project | Install from PyPI |
Both paths create the same three .yml files and the
Bash launcher provided below. This guide includes the
complete configuration and script contents; PyPI users can follow it without
cloning the repository.
The maintained interactive executable is friday-chat, supplied by the
friday-chat distribution and imported as friday_chat. The separate friday
entry point in friday-framework-cli is a placeholder in this release; use
friday-chat for these instructions.
The examples target 0.1.0a3. Installing the entire framework includes optional packages and adapters; it does not activate tools, speech or external services. The initial configuration enables real conversation and memory, with tools and speech disabled. Chat's orchestration and speech adapters remain deterministic even in real mode; these instructions do not establish live audio or specialist agent execution. See capability status.
Prerequisites and decisions
Before a real session, you need:
- Python 3.13.4 or newer, an isolated virtual environment, and pip or uv.
Check the patch version with
python --version. UC1 also needs Git and uv. - Access to chat and embedding endpoints. Use hosted APIs, local servers, or a mixture. Hosted services require an account, model access and credentials; local serving requires you to run the models yourself. The OpenAI example needs no local model server. Ollama and LM Studio are optional local alternatives.
- Exact API model identifiers, supported context sizes, and the selected provider's credentials. For local serving, a download name can differ from its API ID. Confirm model access and identifiers with your provider/server.
- A writable client directory for configuration, transcripts, vector data, graph data and recovery records. Keep it stable between launches.
- A model-role plan. At minimum, real canonical startup needs the primary chat service, extraction and four maintenance roles. The examples define all roles, sharing one chat profile initially, plus a separate embedding profile.
- A supported shell. Commands and the launcher below target Bash on
macOS/Linux. WSL is an option for a Bash workflow on Windows; native
PowerShell needs an equivalent launcher and
.venv\Scripts\friday-chat.exe.
The complete installation can bring native/platform dependencies for optional
adapters, especially audio. Consult the relevant package README if installation
fails there. Core Chat does not require a microphone, Docker, a paid provider,
or a telemetry account. If you want the smaller standard framework installation,
use friday-framework==0.1.0a3 without [all]; it still includes Chat. This guide's
full-install commands deliberately use [all] or all workspace packages/extras.
UC1: install from a clone
Run these commands in the parent directory where you want the checkout:
git clone https://github.com/CIChuck/agent-framework.git
cd agent-framework
python3.13 --version
uv sync --python 3.13 --all-packages --all-extras --locked
source .venv/bin/activate
python --version
friday-chat --version
friday-chat --help
Verify the installed interpreter is at least 3.13.4, and the checkout and
reported Friday version match the 0.1.0a3 basis of this guide. If your branch
is newer, consult its matching guides. The Python minor selector 3.13 lets uv
select an available compatible patch; it is not a request for Python 3.13.0.
--all-packages selects the entire workspace; --all-extras includes optional
dependencies; --locked preserves the checked-in dependency resolution and fails
rather than silently updating it. Workspace packages are editable: this
.venv/bin/friday-chat uses the cloned source. You do not also need a PyPI
installation in that environment. See uv workspace behavior.
Keep the terminal at the repository root for the next step. The client files
will live inside .friday/chat-client/, which this repository already ignores.
The repository's example launcher
points to broad example configuration
and a machine-local environment file. It is useful as a pattern; the dedicated
launcher below uses your own files and avoids editing distributed templates.
Continue with Create your client directory.
UC2: install from PyPI
Activate your existing compatible virtual environment, then choose one method below. Run commands from your own application/project directory, outside the Friday source checkout. Keep the Friday distribution cohort on one version.
Option A: pip in an existing virtual environment
python --version
python -m pip --version
python -m pip install "friday-framework[all]==0.1.0a3"
python -m pip check
friday-chat --version
friday-chat --help
python -m pip binds installation to the selected interpreter. The aggregate
friday-framework[all] installs the framework's optional package groups and
friday-chat; a separate pip install friday_chat is unnecessary. There is no
friday_framework module to import: the root distribution is metadata-only.
Option B: uv add in an existing uv project
Use this when your application has a pyproject.toml and uv-managed dependencies.
Activate its Python >=3.13.4 environment first; --active explicitly selects that
active environment rather than silently choosing a different project .venv.
python --version
uv add --active "friday-framework[all]==0.1.0a3"
friday-chat --version
friday-chat --help
This updates your project's dependency declaration, lockfile and selected
project environment. For a bare virtual environment without a uv project,
use pip above, or uv pip install --python "$VIRTUAL_ENV/bin/python" "friday-framework[all]==0.1.0a3"; uv add is a project operation. Do not run
uv init inside the Friday monorepo to set up an independent installed client.
See uv environments and
active project environments.
Keep this environment activated and remain in your application directory for
the shared steps. Installed wheels include templates as package resources, but
you do not need a packages/ directory or the repository's scripts to run Chat.
You will create the following smaller, complete configuration yourself.
Create your client directory
For either use case, run from the chosen checkout/application root, with the correct environment still activated:
CLIENT_DIR="$PWD/.friday/chat-client"
mkdir -p "$CLIENT_DIR"
Use a new directory for this walkthrough. If these filenames already exist,
back them up and reconcile their contents instead of overwriting them. Keep the
CLIENT_DIR variable in this terminal while following the remaining steps.
Your finished layout will be:
<checkout-or-application>/
├── .venv/ # or your existing environment elsewhere
└── .friday/chat-client/
├── config.yml # Chat runtime settings and role bindings
├── models.yml # endpoint, credential references and profiles
├── cli.yml # terminal appearance and progress messages
├── friday.env # selected executable and process environment
├── run-friday-chat.sh # your launcher
└── data/ # created as the real runtime writes state
├── vector/ # Chroma collections
├── graph.json # graph sibling of vector/
├── transcripts/
│ └── friday_transcripts.sqlite
├── recovery/
└── reorganization_logs/
In UC2, add .friday/ to your application's .gitignore if it is not already
ignored. friday.env is executable shell input; keep it private and source only
a file you control. Real conversation and extracted data also need appropriate
retention and backup. The guide uses synthetic values for setup.
Understand the three configuration files
| File | Owner | What belongs here |
|---|---|---|
config.yml |
friday_chat.config.load_friday_py_config() |
Role bindings, memory paths/budgets, identity, extraction, tools and optional integrations |
models.yml |
friday.model-library/v1 |
Server addresses, credential references, exact model identities and shared generation defaults |
cli.yml |
Friday CLI display resolver | Colors, banner, response styling and progress messages |
.yml and .yaml are both YAML filenames. The explicit launch arguments below
select the .yml files. Without --cli-config, automatic sibling lookup looks
for cli-config.yaml, not cli.yml; otherwise it uses built-in defaults.
There is no implicit discovery of this runtime file and no init or doctor
subcommand in alpha3. A headless RuntimeConfig file has a different schema;
use the Chat schema shown here.
Choose hosted APIs or local model serving
Friday can use hosted model APIs, local servers, or different providers for different roles. Its LiteLLM-backed LLM layer supports routes such as OpenAI, Anthropic and OpenRouter. Model availability, supported controls and embedding capability depend on the chosen route. A chat API does not automatically supply an embedding model; configure both roles explicitly.
| Setup | What you operate or obtain | Next step |
|---|---|---|
| Hosted OpenAI chat and embeddings | OpenAI API project, credentials, model access and API usage allowance | Complete OpenAI model library |
| Local Ollama | Running Ollama server with chat and embedding models | Ollama setup |
| Local LM Studio | Running LM Studio server with chat and embedding models | LM Studio setup |
| Mixed providers | A compatible endpoint and credential for each selected chat/embedding role | Define separate endpoint/profile entries and bind each role |
For hosted OpenAI, skip the local-server instructions below. You do not need to download model weights, start Ollama/LM Studio or size a local GPU. Requests go to the configured HTTPS API and use your provider's quotas/billing. Memory files remain at your configured local paths, while text sent for chat, extraction or embeddings is processed by the selected API provider.
For local serving, start Ollama or LM Studio before the live preflight and real Chat launch. Friday does not download or start those models. Choose models your machine can run together or allow for load/unload latency.
All three complete examples below use OpenAI Chat Completions and embeddings
interfaces, directly or through a compatible server. Friday stores the base
address in api_base; the OpenAI SDK calls its corresponding setting base_url.
Other providers need their own LiteLLM route/model and compatible settings;
changing only the URL in the OpenAI example is not a complete Anthropic setup.
Ollama
Install Ollama, then make these example models available locally:
ollama pull qwen2.5:7b
ollama pull nomic-embed-text
ollama list
These are reproducible example identities, not a model-quality ranking. You can substitute another instruction model and embedding model after updating their profiles. Qwen2.5 is the chat example; nomic-embed-text is an embedding-only example, not a conversational model.
If Ollama is not already running as an application/service, start it in another terminal with a context capacity matching this guide:
OLLAMA_CONTEXT_LENGTH=8192 ollama serve
For an existing managed server, configure that server's environment and restart it as described in the Ollama FAQ. Do not start a second server on an occupied port. Changing an environment variable only in the Friday shell does not reconfigure an already running server.
The local compatible base address is http://127.0.0.1:11434/v1. Keep /v1;
do not use Ollama's native /api path in these profiles. The local server ignores
the required client key value; the example supplies local-only. Cloud-backed
Ollama routes have different credential requirements. See
Ollama OpenAI compatibility.
LM Studio
Install LM Studio, download an instruction/chat model and a separate text-embedding model, and make both available to its local server. In the Developer view, start the server and copy the exact API model IDs. Set the chat model's served context to at least 8192 tokens for this example; download size, quantization and context length must fit your machine.
The examples use http://127.0.0.1:1234/v1. Configure the actual port if yours
differs. If authentication is enabled, use the server's actual token rather than
local-only. See LM Studio server setup
and embedding endpoint.
Do not substitute LM Studio's separate native REST address/route into these
OpenAI-compatible profiles.
For either local server, listing IDs is a live local request:
# Ollama; change 11434 to 1234 for an unauthenticated LM Studio server.
curl --fail --silent --show-error http://127.0.0.1:11434/v1/models
For an authenticated server, use its documented authentication when listing models. Confirm that the chat ID and embedding ID below are actually served. A downloaded file by itself is not proof of an available API route.
Write models.yml: endpoints and model profiles
Save one of the following complete examples as $CLIENT_DIR/models.yml.
All three expose the same two profile names, so the shared config.yml works
with any one of them.
A profile is a reusable model definition; a service is a runtime role bound to
that definition. The roles below share one chat profile and one embedding
profile; hosted users access those models through the API instead of downloading them.
Complete hosted OpenAI model library
Use this option for both UC1 and UC2 if you want hosted chat and embeddings.
You need an OpenAI API project/key with access to the selected models and enough
API usage allowance. Obtain the key from your OpenAI API project, then export it
as OPENAI_API_KEY using the environment setup below.
The local-only placeholder used by Ollama is not an OpenAI credential. See the
official authentication reference.
Save this complete alternative as $CLIENT_DIR/models.yml:
schema: friday.model-library/v1
credentials:
openai:
env: OPENAI_API_KEY
endpoints:
openai:
api_base: https://api.openai.com/v1
provider: openai
serving_engine: openai
default_credential: openai
resilience:
max_retries: 2
timeout_seconds: 120
profiles:
chat_model:
kind: chat
endpoint: openai
dialect: openai_chat_completions
model: openai/gpt-5.4-mini-2026-03-17
model_target:
model_id: gpt-5.4-mini-2026-03-17
family: gpt_5_4
revision: gpt-5.4-mini-2026-03-17
generation:
sampling:
temperature: 0.2
max_tokens: 2048
memory_embedding:
kind: embedding
endpoint: openai
dialect: openai_embeddings
model: openai/text-embedding-3-small
model_target:
model_id: text-embedding-3-small
family: text_embedding_3
revision: openai-api-alias-text-embedding-3-small
embedding_options:
batch_size: 16
cache_size: 100
The chat profile uses a documented GPT-5.4 mini snapshot
and its Chat Completions route. This example leaves reasoning controls unset;
the model's documented default effort is none. Check parameter support before
switching model families or adding reasoning controls, especially when retaining
the runtime's temperature overrides. The installed LiteLLM adapter maps Friday's
max_tokens cap to the OpenAI request's appropriate completion-token field.
The embedding profile uses text-embedding-3-small.
Its revision records the API alias, not a pinned dated embedding snapshot.
Keep that model choice consistent with existing collections and validate any
provider/model change as described in the embedding section below.
The profile keys chat_model and memory_embedding are application labels;
all runtime role bindings below already refer to them. Keep the shared
config.yml, cli.yml and launcher unchanged when selecting this complete
model library. Supply OPENAI_API_KEY instead of a local server credential.
The same key reference serves chat and embeddings in this example. Access and
limits depend on your API project; the live preflight below checks your actual
routes rather than promising account access.
To combine hosted chat with local embeddings, retain both endpoint definitions,
point chat_model.endpoint to OpenAI and memory_embedding.endpoint to your
local server, and declare/export the credential reference for each. All roles
using a profile follow that profile's endpoint. A hosted chat choice alone does
not redirect embeddings or maintenance to the same provider.
Complete Ollama model library
schema: friday.model-library/v1
credentials:
local:
env: FRIDAY_LOCAL_MODEL_KEY
endpoints:
local:
api_base: http://127.0.0.1:11434/v1
provider: openai_compatible
serving_engine: ollama
default_credential: local
resilience:
max_retries: 2
timeout_seconds: 120
profiles:
chat_model:
kind: chat
endpoint: local
dialect: openai_chat_completions
model: openai/qwen2.5:7b
model_target:
model_id: qwen2.5:7b
family: qwen2_5
revision: replace-with-your-installed-ollama-model-digest
generation:
sampling:
temperature: 0.2
max_tokens: 2048
memory_embedding:
kind: embedding
endpoint: local
dialect: openai_embeddings
model: openai/nomic-embed-text
model_target:
model_id: nomic-embed-text
family: nomic_embed
revision: replace-with-your-installed-embedding-model-digest
embedding_options:
batch_size: 16
cache_size: 100
Replace revision with the actual model digest/revision recorded for your
installation. It is provenance metadata, not a command that downloads or pins
a model inside the server. If your server lists a different tag, change both
model and model_target.model_id to match it.
openai/ is LiteLLM's routing prefix for this compatible interface; it does not
mean these requests go to OpenAI's hosted service. The explicit api_base
selects your local server. The wire model ID is the corresponding server ID
without that routing prefix. Do not put the openai/ prefix into model_id.
Complete LM Studio model library
This example assumes the server lists qwen2.5-7b-instruct and
text-embedding-nomic-embed-text-v1.5. Replace those IDs with the exact IDs
from your server, including both each model suffix and model_id. Replace
the revision values with your downloaded artifact/revision information.
schema: friday.model-library/v1
credentials:
local:
env: FRIDAY_LOCAL_MODEL_KEY
endpoints:
local:
api_base: http://127.0.0.1:1234/v1
provider: openai_compatible
serving_engine: lm_studio
default_credential: local
resilience:
max_retries: 2
timeout_seconds: 120
profiles:
chat_model:
kind: chat
endpoint: local
dialect: openai_chat_completions
model: openai/qwen2.5-7b-instruct
model_target:
model_id: qwen2.5-7b-instruct
family: qwen2_5
revision: replace-with-your-installed-lm-studio-chat-revision
generation:
sampling:
temperature: 0.2
max_tokens: 2048
memory_embedding:
kind: embedding
endpoint: local
dialect: openai_embeddings
model: openai/text-embedding-nomic-embed-text-v1.5
model_target:
model_id: text-embedding-nomic-embed-text-v1.5
family: nomic_embed
revision: replace-with-your-installed-lm-studio-embedding-revision
embedding_options:
batch_size: 16
cache_size: 100
Model-library options that matter first
| Setting | Meaning and setup rule |
|---|---|
credentials.<name>.env |
Name of a process variable, never the token itself; the launcher exports its value |
api_base |
Full compatible base including /v1; use a separate endpoint definition if embeddings are hosted elsewhere |
provider, serving_engine, dialect |
Transport/capability identity; keep the values consistent with the route you selected |
model / model_target |
Routing model plus exact served identity, family and recorded revision; an arbitrary friendly label does not load a server model |
timeout_seconds, max_retries |
Shared transport resilience; role-specific resilience_overrides can replace these |
generation.sampling.temperature |
Shared chat default; role overrides below make extraction/maintenance less variable |
generation.max_tokens |
Response cap; it is not the model's total context size or an embedding dimension |
embedding_options |
Embedding batch size and process cache size; these do not change vector dimension |
Canonical model-library schemas reject unknown fields. Add only supported provider/generation controls; copying a provider's native JSON options into a profile can fail validation or exceed that route's capabilities. The examples omit reasoning controls to avoid assuming a particular model's reasoning API. For additional provider/role arrangements, see configuration reference.
Write config.yml: runtime, roles and memory
Save this complete Chat configuration as $CLIENT_DIR/config.yml.
It works with any of the three model libraries above after model IDs and
credentials are correct.
It binds all documented model roles explicitly; the first session needs access to
one chat model plus one embedding model.
model_library:
path: ./models.yml
llm_pool:
default_service: chat
services:
chat:
profile: chat_model
extraction:
profile: chat_model
generation_overrides:
sampling:
temperature: 0.0
max_tokens: 2048
synthesizer:
profile: chat_model
generation_overrides:
sampling:
temperature: 0.0
classifier:
profile: chat_model
generation_overrides:
sampling:
temperature: 0.0
researcher:
profile: chat_model
judge:
profile: chat_model
generation_overrides:
sampling:
temperature: 0.0
compaction:
profile: chat_model
generation_overrides:
sampling:
temperature: 0.0
passage_router:
profile: chat_model
generation_overrides:
sampling:
temperature: 0.0
max_tokens: 512
smart_file_summarizer:
profile: chat_model
smart_file_synthesizer:
profile: chat_model
embedding_pool:
default_service: memory
services:
memory:
profile: memory_embedding
maintenance:
profile: memory_embedding
llm:
max_retries: 0
chat:
user_name: User
assistant_name: Friday
system_prompt: You are Friday, a careful and helpful assistant.
logging:
level: WARNING
extraction_debug: false
extraction_rejections: false
tools_debug: false
extraction:
llm_service: extraction
interval: 3
ontology:
node_types:
person:
description: A named person
examples: [Alex]
project:
description: A named project
examples: [Orchid]
edge_relations:
association: [WORKS_ON, RELATED_TO]
min_label_length: 2
max_label_length: 80
memory:
persist_directory: ./data/vector
collection_name: chat_long_term
context_window: 8192
output_buffer: 2048
max_history_turns: 12
consolidate_after_turns: 15
token_estimator:
strategy: approx
approx_chars_per_token: 4.0
approx_overhead_pct: 0.15
retrieval:
short_term_collection: chat_short_term
long_term_collection: chat_long_term
decayed_collection: chat_decayed
short_term_min_similarity: 0.5
long_term_min_similarity: 0.7
default_n_results: 5
supporting_context:
budget_ratio: 0.25
section_priority: [known_facts, insights, summaries, tools, passages, state]
max_items:
known_facts: 20
insights: 10
summaries: 5
passages: 3
tools: 0
compaction:
enabled: true
llm_service: compaction
compaction_threshold: 0.85
critical_threshold: 0.95
target_utilization: 0.7
cooldown_turns: 3
passage_router:
enabled: false
llm_service: passage_router
priming:
enabled: true
previous_sessions: 2
previous_session_turns: 8
token_budget: 1500
transcript:
export_directory: ./data/transcripts
capture_raw_prompts: false
maintenance:
backup_directory: ./data/recovery
llm:
synthesizer:
llm_service: synthesizer
classifier:
llm_service: classifier
researcher:
llm_service: researcher
judge:
llm_service: judge
embedding:
embedding_service: maintenance
logging:
log_directory: ./data/reorganization_logs
lifecycle:
enabled: true
session:
flush_on_exit: true
lifecycle_on_exit: true
reorganize_on_exit: false
smart_file:
default_add_to_context: true
default_store_to_memory: false
llm:
summarizer:
llm_service: smart_file_summarizer
synthesizer:
llm_service: smart_file_synthesizer
tools:
enabled: false
speech:
enabled: false
telemetry:
enabled: false
langfuse:
enabled: false
Required and optional model roles
| Service name in the example | Used for | Startup/activation rule |
|---|---|---|
chat |
Foreground conversation | Selected by llm_pool.default_service; required for real Chat |
extraction |
Structured entities, relationships, insights and turn summaries | Real maintenance assembly constructs the extractor; define it even before its first scheduled call |
synthesizer |
Memory synthesis | Maintenance roles are resolved during real startup, even with reorganization-on-exit disabled |
classifier |
Classifying claims for maintenance | Same startup requirement |
researcher |
Maintenance evidence/research processing | Same startup requirement; a role name alone does not grant web access |
judge |
Maintenance verification/judgment | Same startup requirement |
compaction |
Summarizing context when its budget is pressured | Used when memory.compaction.enabled is true, as above |
passage_router |
Deciding whether retrieved passages belong in context | Conditional on memory.passage_router.enabled; off above |
smart_file_summarizer |
Summarizing large file sections | Used when a SmartFileReadTool is registered/constructed; tools are off above |
smart_file_synthesizer |
Combining those section summaries | Same smart-file prerequisite |
Embedding memory |
Embedding ingestion and similarity queries | Selected by embedding_pool.default_service in real Chat assembly |
Embedding maintenance |
Explicit reorganization embedding provider | Selected by maintenance.embedding.embedding_service; kept compatible with memory |
These service names are local configuration keys, not models you must download
separately. chat_model and memory_embedding are the reusable profile keys in
models.yml. To use a different extraction model, add a second chat profile
there and change only llm_pool.services.extraction.profile. Do the same for any
role requiring a larger/faster model or a different endpoint. Change a role's
generation_overrides or resilience_overrides in its service binding; endpoint
defaults remain shared. Never bind an embedding profile to a chat service.
All three canonical sections—model_library, llm_pool, embedding_pool—must
appear together. Every declared service is resolved when the configuration
loads, including roles not yet enabled. Remove unused hosted bindings or supply
their selected credentials; disabling a feature does not excuse an unresolved
model-library credential. A missing maintenance service can prevent startup;
a caught optional adapter error can instead appear as a runtime gap. Configuration
success alone is not proof that every secondary adapter is functioning.
Runtime options and path rules
model_library.pathis resolved relative to config.yml. Keepmodels.ymlbeside it, or use an absolute path. This differs from data paths.- Memory/transcript/recovery paths above are relative to the process working
directory. The launcher changes to the client directory before Chat starts.
If you launch directly from elsewhere, use absolute data paths or perform that
same
cd; otherwise you can accidentally select a different empty store. context_window: 8192is Friday's context budget. Configure at least that capacity on the model server; Friday does not resize the server's model context.output_buffer: 2048reserves response room. Keep the model's output cap and budget aligned, then tune history/supporting context to your workload.llm.max_retries: 0disables Chat's additional whole-turn retry loop; endpoint/service transport retries still apply. This avoids multiplying two retry layers. An optionalllm.timeout_secondssets the foreground turn timeout and the primary request timeout; secondary services retain their own resolved resilience settings. Increase time budgets deliberately for slow local inference rather than adding retry layers.extraction.interval: 3schedules extraction every three turns.0means every turn;-1disables interval-triggered extraction. Extraction also participates in configured exit flushing, so an interval setting alone is not a universal no-model-calls switch. JSON-producing extraction quality matters independently of conversational fluency; the built-in prompt is used when none is supplied.lifecycle.enabledselects persistent graph/lifecycle services. Vector memory, transcripts and graph memory are different stores. Compaction is opt-in here; its role can make extra model calls when budget thresholds are reached.session.flush_on_exitlets pending extraction settle;reorganize_on_exitremains false for this initial setup. Exit normally rather than killing the process while writes/background work are active.capture_raw_prompts: falseavoids opting into raw prompt capture; transcript records still contain conversation content. It is not a global privacy switch.- Tools, speech and telemetry are off independently. Full installation does not supply credentials or permission to activate them. Optional Langfuse backend work remains queued; the legacy callback configuration is a separate path.
These are initial settings, not a complete catalog of every advanced memory, security, tool or MCP option. Continue with configuration, memory and memory budgeting after the first working session.
Embedding setup: how memory gets its vectors
The chat model generates text; an embedding model converts text into a numeric vector so memory can find related records. Installing Chroma or choosing an embedding-looking name does not provide that model. It must be available at an endpoint that actually implements embeddings, whether hosted or local.
With the OpenAI library, both regular memory and maintenance use
text-embedding-3-small through https://api.openai.com/v1. OpenAI's
embedding guide
documents its default vector length as 1536. Friday alpha3 uses that model's
default output dimensions here; its canonical options do not expose OpenAI's
dimensions parameter. Text submitted for storage/query embedding leaves the
client machine and can incur API usage. The Chroma files themselves remain in
memory.persist_directory; hosted embeddings do not move that database to OpenAI.
The examples make the route explicit:
models.yml: profiles.memory_embedding
↓
config.yml: embedding_pool.services.memory.profile = memory_embedding
↓
config.yml: embedding_pool.default_service = memory
↓
real Chat's embedding adapter → memory ingestion and retrieval
In alpha3 real Chat assembly, the pool default selects the regular embedding
adapter. A standalone embedding.embedding_service entry does not override that
selection. Explicit maintenance uses its separate
maintenance.embedding.embedding_service reference; this guide binds both to
the same profile to keep the stored vector space consistent.
What you must keep compatible
| Item | Why it matters |
|---|---|
| Actual embedding model and revision | Stored and query vectors must come from the same compatible embedding space |
| Vector dimension | The server determines the returned vector length; changing it can make an existing Chroma collection incompatible |
| Preprocessing and model task-prefix conventions | These affect similarity; validate the chosen model's retrieval behavior rather than assuming any same-sized vector is interchangeable |
| All three collection names and persistence directory | They select your existing short-term, long-term and decayed collections; changing them can look like missing memory |
| Maintenance embedding binding | Synthesized/maintenance records must remain compatible with ordinary memory queries |
There is no dimensions setting in alpha3's canonical embedding_options.
The supported options here are batch_size and cache_size; neither changes the
vector length. Friday's Chat adapter does not configure a query/document prefix
policy in this example. If your selected embedding model requires task-specific
preprocessing, verify that your serving/integration path provides it; do not
invent a YAML field to request it. The small live probe below checks availability
and vector length, not retrieval quality.
Before replacing an embedding model, stop the old client, retain a consistent
backup and the source records, choose a new persistence directory and new
collection names, and re-embed/reingest the intended content through a supported
workflow. Do not point an incompatible model at an existing collection, even if
it happens to return the same dimension. Changing revision in YAML does not
migrate existing vectors. Keep existing data until you have verified the new
retrieval behavior. See memory recovery and operations.
Write cli.yml: terminal presentation
Save this complete display configuration as $CLIENT_DIR/cli.yml:
theme:
error: bold red
warning: bold yellow
success: bold green
info: bold blue
muted: dim
highlight: bold cyan
icons:
error: X
warning: '!'
success: OK
info: i
banner:
enabled: true
style: panel
title: Friday
subtitle: '{assistant_name} CLI'
show_version: true
border_style: cyan
tips_enabled: false
prompt:
style: bold cyan
name_style: bold cyan
separator_style: white
continuation_style: dim
response:
prefix: true
name_style: bold green
separator_style: green
text_style: white
spinner:
spinner_type: dots
text_style: dim
spinner_style: cyan
randomize: false
thinking_messages: [Thinking...]
tool_messages: [Working...]
theme and icons set terminal styles; banner controls the startup display;
response controls the assistant prefix/colors; spinner supplies wait-state
presentation. The Chat identity still comes from config.yml. In alpha3 the
Chat input adapter formats its prompt as <user_name>: ; declaring prompt styles
does not change that text. Spinner/tool messages do not enable tools.
This file contains no model endpoints, credentials, memory paths or command
permissions. An invalid/missing explicit file is an error. If you prefer
built-in styling, omit --cli-config from your launcher; remember the sibling
cli-config.yaml lookup described above.
Create friday.env and the launcher
Capture the correct installed executable
With the UC1 or UC2 environment still activated, create friday.env automatically.
This offline setup command uses that interpreter's scripts directory and
refuses to overwrite an existing environment file:
export CLIENT_DIR
python - <<'PY'
import os
import shlex
import sysconfig
from pathlib import Path
client_dir = Path(os.environ["CLIENT_DIR"])
executable = Path(sysconfig.get_path("scripts")) / "friday-chat"
if not executable.is_file():
raise SystemExit(f"Friday Chat is not installed in this interpreter: {executable}")
env_file = client_dir / "friday.env"
with env_file.open("x", encoding="utf-8") as stream:
stream.write(f"export FRIDAY_CHAT_BIN={shlex.quote(str(executable))}\n")
stream.write("export FRIDAY_LOCAL_MODEL_KEY=local-only\n")
env_file.chmod(0o600)
print(f"Created {env_file}; executable: {executable}")
PY
For the local-server variants, the resulting shell file resembles:
export FRIDAY_CHAT_BIN='/absolute/path/to/your/environment/bin/friday-chat'
export FRIDAY_LOCAL_MODEL_KEY='local-only'
Keep local-only for an explicitly local server that accepts an unused client
key. For an authenticated LM Studio/server route, edit that value privately to
its real token. credentials.local.env in models.yml names this variable;
it does not embed its value. Avoid publishing the file or displaying real tokens
in diagnostics. Recreate/update the executable path if you move the environment.
For the hosted OpenAI model library, this generated local placeholder is unused;
follow the next step to supply OPENAI_API_KEY. You may remove the unused
FRIDAY_LOCAL_MODEL_KEY line from friday.env.
Chat does not automatically load .env files. The launcher deliberately
sources friday.env. Ordinary ${VARIABLE} strings in runtime YAML are expanded
before validation, including strings in disabled sections; every such variable
must be supplied. The canonical credential env: value above is a literal
reference resolved for each declared service. CLI display YAML is not the place
for environment-variable substitution or provider secrets.
Supply the OpenAI API key
OpenAI users: after creating friday.env, run the following in the Bash
terminal that will launch Chat. It prompts without echoing the key or putting
its value into a command in shell history:
read -r -s -p "OpenAI API key: " OPENAI_API_KEY
printf '\n'
export OPENAI_API_KEY
This export is inherited by the launcher and both configured API services. Keep it available for the offline configuration/fake checks too: those checks resolve the credential reference even though they make no API call. For a purely offline fake check, a synthetic nonempty value can satisfy the reference; a real session requires a valid project credential.
In a new terminal, supply the key again or inject it through your secret manager.
For a persistent local launcher setup, you can instead add an
export OPENAI_API_KEY=... assignment privately to your mode-0600 friday.env.
Use a correctly shell-quoted value; never commit that file or put the key into
models.yml, config.yml, cli.yml or the script itself. Avoid adding an empty
or placeholder assignment to friday.env that would overwrite a valid exported
key. The launcher sources this file, so assignments there take precedence over
its inherited environment.
The shared launcher needs no provider-specific flag. The selected models.yml
chooses the API endpoint, model and OPENAI_API_KEY credential reference. Its
FRIDAY_LOCAL_MODEL_KEY setting has no effect on the OpenAI profiles.
Save run-friday-chat.sh
Save this complete script as $CLIENT_DIR/run-friday-chat.sh:
#!/usr/bin/env bash
set -euo pipefail
CLIENT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
MODE="${1:-real}"
if [[ "$#" -gt 1 ]] || [[ "$MODE" != real && "$MODE" != fake ]]; then
echo "Usage: $0 [real|fake]" >&2
exit 2
fi
for name in friday.env config.yml models.yml cli.yml; do
if [[ ! -f "${CLIENT_DIR}/${name}" ]]; then
echo "Missing client file: ${CLIENT_DIR}/${name}" >&2
exit 1
fi
done
cd "$CLIENT_DIR"
source "${CLIENT_DIR}/friday.env"
: "${FRIDAY_CHAT_BIN:?Set FRIDAY_CHAT_BIN in friday.env}"
if [[ "$FRIDAY_CHAT_BIN" != /* || ! -x "$FRIDAY_CHAT_BIN" ]]; then
echo "FRIDAY_CHAT_BIN must be an absolute executable path." >&2
exit 1
fi
# The environment takes precedence over --runtime in alpha3: set both explicitly.
export FRIDAY_CHAT_RUNTIME="$MODE"
exec "$FRIDAY_CHAT_BIN" \
--runtime "$MODE" \
--config "${CLIENT_DIR}/config.yml" \
--cli-config "${CLIENT_DIR}/cli.yml"
Then make it executable:
chmod u+x "$CLIENT_DIR/run-friday-chat.sh"
This script works from another working directory because it locates its own
files and changes to their directory before starting Chat. It selects the saved
virtual-environment executable without requiring activation on later launches.
Its default is real; the first verification below deliberately passes
fake. It normalizes FRIDAY_CHAT_RUNTIME so an inherited value cannot silently
change the selected mode. It does not start model servers or install/update any
packages. The only optional positional argument is real or fake.
Validate configuration before calling models
Run this offline check from the same activated installation environment:
cd "$CLIENT_DIR"
source ./friday.env
python - <<'PY'
from pathlib import Path
from friday_chat.config import load_friday_py_config
from friday_chat.display import resolve_display_config
config = load_friday_py_config(Path("config.yml"))
display = resolve_display_config(
config_path=Path("config.yml"), cli_config_path=Path("cli.yml")
)
print("Chat services:", ", ".join(config.llm_service_specs))
print("Embedding services:", ", ".join(config.embedding_service_specs))
print("Display source:", display.source)
print("Configuration parsed and model bindings resolved; no model call made.")
PY
Expect ten chat service names, embedding services memory, maintenance, and
Display source: explicit. This verifies syntax, schema, selected credential
references and profile resolution. It does not contact the server, validate
model availability, test extraction quality or guarantee runtime readiness.
Check the terminal flow independently of providers:
"$CLIENT_DIR/run-friday-chat.sh" fake
Enter a short greeting, then /q to exit. Fake mode supplies deterministic
responses. Canonical configuration still loads, so its declared credential
references must resolve; it does not require real model connectivity. Fake mode
is not proof of persistence or semantic recall.
Live preflight for chat and embeddings
For OpenAI, ensure OPENAI_API_KEY is available. For local serving, start the
configured server. Run this live check from the client directory and activated
environment. It reads the selected profiles rather than hardcoding a different
model/endpoint, and sends synthetic text to both APIs. Hosted profiles make real
provider requests and consume API usage:
cd "$CLIENT_DIR"
source ./friday.env
python - <<'PY'
import asyncio
from pathlib import Path
from friday_chat.config import load_friday_py_config
from friday_llm import (
ChatCompletionRequest, LiteLLMEmbeddingService, LiteLLMService,
close_litellm_async_clients,
)
async def main() -> None:
config = load_friday_py_config(Path("config.yml"))
chat_spec = config.llm_service_specs[config.llm_pool.default_service]
embedding_spec = config.embedding_service_specs[config.embedding_pool.default_service]
chat = LiteLLMService.from_spec(chat_spec)
embedding = LiteLLMEmbeddingService.from_spec(embedding_spec)
try:
reply = await chat.chat_completion_request(ChatCompletionRequest(
messages=({"role": "user", "content": "Say hello in one short sentence."},)
))
if not reply.content:
raise RuntimeError("Chat server returned no text content")
vector = await embedding.embed_query("The Orchid project uses a green notebook.")
if not vector:
raise RuntimeError("Embedding server returned an empty vector")
print("Chat reply:", reply.content)
print("Embedding vector length:", len(vector))
finally:
await close_litellm_async_clients()
asyncio.run(main())
PY
A nonempty response and numeric vector confirm basic connectivity for those routes. Repeat setup for any role you later bind to a different profile. A model can chat successfully yet produce malformed extraction JSON or have inadequate context capacity. This preflight does not certify those behaviors. For hosted profiles it becomes a provider call with that provider's data/cost implications.
Start and verify real sessions
Launch with your selected endpoints ready: OpenAI credentials/model access for the hosted path, or the configured model server for the local path:
"$CLIENT_DIR/run-friday-chat.sh" real
For a first synthetic conversation, introduce a distinctive fact such as “The Orchid project uses a green notebook,” ask a follow-up, and continue for at least three turns so interval-based extraction can run. Wait for responses and exit normally. Background work can make additional chat/embedding requests; the endpoint must remain available while it settles.
Start the script again for another chat session. Each launch gets a new session
identity; the same stable data paths retain the transcript/vector/graph stores.
Previous-session context/priming is not an exact continuation of the old live
session. Check saved records independently of whether a model happens to recall
the fact. The guide's priming settings limit how much prior context is selected.
Use the existing CLI reference as further reference for session/history/transcript inspection, memory/context diagnostics, session management and other chat commands. It describes the commands and their side effects; this quick start intentionally does not repeat that catalog.
For a direct equivalent to the script, run from the client directory:
cd "$CLIENT_DIR"
source ./friday.env
FRIDAY_CHAT_RUNTIME=real "$FRIDAY_CHAT_BIN" \
--runtime real --config "$CLIENT_DIR/config.yml" --cli-config "$CLIENT_DIR/cli.yml"
On later days you can use the launcher's absolute path, for example
/your/application/.friday/chat-client/run-friday-chat.sh real, without first
activating the environment. CLIENT_DIR is only a convenience variable in the
setup terminal; it is not automatically preserved in a new shell.
What to verify before adding features
| Check | Evidence to look for |
|---|---|
| Installation | Correct friday-chat version and intended environment path |
| Runtime/model files | All ten chat bindings and two embedding bindings resolve; real mode selected |
| Chat | A live response from the intended provider/server and model |
| Memory | Successful extraction and nonempty stored records; no adapter-gap/extraction failures |
| Restart | Earlier transcript/records accessible with the same data paths |
| Retrieval | The relevant record appears in selected context, not just somewhere in storage |
| Shutdown | Background extraction/write work settles without lifecycle errors |
If an endpoint is unreachable, check Internet/API access for hosted services or
the server process/port for local serving, then the /v1 base and exact model ID.
A 401 usually means its selected credential is wrong or absent; hosted quota,
billing or rate-limit failures need their provider/project checks.
An unknown service/profile means the role keys do not match. A schema error can
mean a legacy/headless setting was placed in Chat YAML. A new empty store often
means you changed cwd, a directory or a collection name. Do not delete live
SQLite/Chroma lock files or reset data as a setup repair.
After this baseline works, enable one optional integration at a time using tools, MCP client setup, or advanced integration. For deeper configuration and recovery, see configuration reference and troubleshooting.