Study from course documents with a grounded academic assistant, and generate review materials when you need them through a persistent desktop chat workflow.
- Ingest course materials (PDF, DOCX, CSV, and common text/code formats such as TXT, Markdown, JSON, HTML, XML, and source files)
- Classify documents by type for optimized processing
- Chunk documents using type-specific multi-stage splitting strategies
- Embed into a local Chroma vector store
- Retrieve context with task-aware weighting across document types
- Chat with an LLM in a session-aware study-assistant workflow
- Ask grounded course questions and get guided review help from uploaded materials
- Generate structured study artefacts such as review summaries, mock exams, and practice booklets when requested
- Save canonical generated output as Markdown, with optional DOCX/PDF export in the desktop GUI
- Persist desktop sessions, settings, and chat history across app restarts
This project is released under the MIT License. See LICENSE.
UACRAgent is designed so that most working data stays on your machine, but it can still send selected content to third-party model providers depending on how you configure it.
What is stored locally:
- Desktop session state is saved on disk so you can reopen sessions later.
- Session data includes course settings, selected file paths, chat history, chosen provider/model settings, and session UI preferences.
- Session state is stored in
<workspace>/.uacragent/session.json. - Retrieved document indexes are stored locally in
<workspace>/.uacragent/chroma_db/. - Generated outputs are stored locally in
<workspace>/.uacragent/outputs/. - When files are copied into a workspace, they are stored under
<workspace>/.uacragent/uploads/. - Local embedding models are cached under
<app_data_dir>/models/. - In frozen standalone app builds, the ONNX local embedding model is also kept
inside
<app_data_dir>/models/chroma/onnx_models/.
What is not written to session files:
- Desktop-entered API keys are kept in process memory only.
- The session persistence layer intentionally does not write provider API keys to disk.
What may be sent to external providers:
- Chat requests may send your message, selected chat attachments, course metadata, recent chat history, and retrieved document excerpts to the active LLM provider.
- Document-generation requests may send course metadata, planning context, retrieved document chunks, and generation instructions to the active LLM provider.
- If you use cloud embeddings (
geminioropenai), document chunks are also sent to that embedding provider during indexing. - If you enable provider-backed web search or file-attachment features in the desktop chat, the relevant request content is also handled by the selected provider.
Provider and deployment notes:
- If you want to minimize cloud data sharing, use
EMBEDDING_PROVIDER=local. This still leaves chat/generation requests going to the selected LLM provider unless you also choose a different runtime architecture outside the current app. - Local embeddings download their model backend on first use, then reuse the local cache afterward.
- On first launch, the desktop GUI shows a privacy notice that must be accepted before use. You can reopen the notice later from App Settings, and the session settings dialog also shows a provider-specific privacy reminder and privacy-policy link.
- The FastAPI interface accepts absolute file paths. Without
UACRAGENT_ALLOWED_BASE_DIR, a local API server can read any absolute existing file path supplied in a request. The current API is intended for local trusted use only; if you still want an extra filesystem safety fence, setUACRAGENT_ALLOWED_BASE_DIR. - Deleting a session removes the
<workspace>/.uacragent/bundle. Original source files outside that folder are not deleted.
You are responsible for choosing providers, deployment settings, and input documents that meet your own privacy, institutional, and regulatory requirements.
UACRAgent is an educational study-assistance tool. It can help summarize materials, answer grounded questions, and generate review artefacts, but it may still produce incorrect, incomplete, outdated, or misleading content.
UACRAgent is an independent open-source project. It is not affiliated with, endorsed by, or officially connected to OpenAI, Google, DeepSeek, or any university, school, examination body, or educational institution.
Please keep in mind:
- Generated summaries, mock exams, predictions, and explanations are study aids, not official course materials.
- The app does not guarantee exam accuracy, topic coverage, grading alignment, or factual correctness.
- You should verify important claims, formulas, deadlines, policies, and exam expectations against your instructor, syllabus, textbook, and other official sources.
- Do not rely on this project as a substitute for professional, legal, medical, financial, or institutional advice.
- If you upload sensitive or confidential documents, review your provider and deployment choices carefully before use.
- Third-party LLM and embedding providers may apply their own privacy policies, retention practices, and terms of service when processing requests sent from this app.
The project currently has three user-facing interfaces:
- Desktop GUI: the primary interface, now built as a persistent conversational assistant with session management
- CLI: interactive conversational terminal interface that indexes documents once, then answers questions and generates study documents on request
- FastAPI API: programmatic one-shot document generation
The assistant supports four distinct generated output modes:
| Task | Description |
|---|---|
| Review Summary | Comprehensive review with key concepts, definitions, tips, and sample questions |
| Practice Booklet | Structured collection of practice problems (easy/medium/hard) with solution key |
| Mock Exam | Realistic exam paper with point allocations and a separate answer key |
| Exam Prediction | Two-part output: Part A — topic-by-topic prediction analysis (confidence level, reasoning, study approach, sample questions); |
| Part B — a complete predicted exam paper with realistic questions, mark allocations, and a full answer key / marking guide |
Each task uses dedicated planner and writer prompts tuned for its output format.
The project supports multiple LLM providers for chat, planning, and writing:
| Provider | Use Cases | Desktop Chat Extras | Required Key |
|---|---|---|---|
| Gemini | Chat, planning, writing, embeddings | Web search + file attachments | GOOGLE_API_KEY |
| OpenAI | Chat, planning, writing, embeddings | Web search + file attachments | OPENAI_API_KEY |
| DeepSeek | Chat, planning, writing | Standard chat only | DEEPSEEK_API_KEY |
Model note:
- Desktop chat attachment controls are gated by the active provider and model.
For example, OpenAI
*-search-previewmodels support built-in web search but disable the upload button because they do not accept file/vision inputs.
Document retrieval embeddings are configured independently from the chat/writer LLM provider:
| Provider | Use Cases | Requirements |
|---|---|---|
| Gemini | Cloud embeddings | GOOGLE_API_KEY |
| OpenAI | Cloud embeddings | OPENAI_API_KEY |
| Local | On-device embeddings | No API key; first use downloads a model |
The desktop GUI exposes all three embedding options. Local embeddings are free to run after the model has been downloaded and cached.
Backend note:
- In source installs,
EMBEDDING_PROVIDER=localuses thesentence-transformers/ HuggingFace stack. - In frozen standalone app builds, local embeddings use Chroma's ONNX-based
all-MiniLM-L6-v2path instead of the PyTorch stack for packaging reliability, but the downloaded model still stays inside<app_data_dir>/models/.
Users specify the kind of exam they are preparing for:
| Exam Type | Description |
|---|---|
| Quiz | Short, focused assessment |
| Midterm | Mid-semester examination |
| Final | End-of-semester comprehensive exam |
| Term Test | In-term test |
| Other | Custom or unspecified |
The exam type influences prompt behavior — a quiz review is concise and focused while a final review is comprehensive.
When generating output you can supply context about the course. The Course Name is required; all other fields are optional but improve the quality and relevance of the output.
| Field | Required | Example |
|---|---|---|
| Course Name | Yes | Introduction to Algorithms |
| University | No | University of Toronto |
| Major / Department | No | Computer Science |
| Course Code | No | CSC263 |
| Professor | No | Dr. Jane Smith |
| Semester | No | Fall 2024 |
| Exam Duration | No | 2 hours or 90 minutes |
| Exam Info Sheet | No | Closed book. One formula sheet allowed. Topics: chapters 1-6. |
All fields are passed to every planner and writer prompt, so the LLM can tailor content to the specific course and context. The Exam Duration and Exam Info Sheet fields are especially useful for generating realistic mock exams and practice booklets that match the actual exam constraints.
Interface note:
- The desktop GUI accepts an exam info sheet file from the Session Settings dialog.
- When the desktop exam info sheet is changed or cleared later, the old workspace-local copied file is cleaned up automatically.
- The API accepts
exam_infoas plain text in the request body. - The current CLI does not expose a dedicated exam-info argument.
Each document type uses a multi-stage splitting pipeline optimized for its structure:
| Type | Splitting Strategy | Final Chunk Size |
|---|---|---|
| Textbook | Markdown header split (chapter/section/subsection) then recursive character split | 1500 |
| Syllabus | Markdown header split (section/subsection) then recursive character split | 800 |
| Lecture Notes | Sentence-aware recursive split (preserves slide bullet points) | 1000 |
| Past Exam | Question-boundary regex split (Q1, 1., Part A, (a), etc.) then recursive split | 500 |
| Assignment | Problem-boundary regex split (Problem/Exercise/Task headers) then recursive split | 600 |
| Other | Standard recursive character split | 1000 |
Multi-stage pipelines feed each stage's output into the next. For example, a textbook
PDF is first split on #/##/### markdown headers to isolate chapters and sections,
then each section is recursively split into retrieval-sized chunks. Header-based
metadata (chapter, section, subsection) is preserved on every chunk.
- Python 3.10+
- At least one LLM API key for generation:
- Google Gemini, or
- OpenAI, or
- DeepSeek
- One embedding option for retrieval:
- Google Gemini embeddings with
GOOGLE_API_KEY, or - OpenAI embeddings with
OPENAI_API_KEY, or - local on-device embeddings with no API key
- Google Gemini embeddings with
Notes:
- Running the pipeline will make paid model requests (LLM + embeddings).
- DeepSeek can be used for chat/planning/writing together with either cloud embeddings or local embeddings.
- Local embeddings download their model backend on first use, then run from the local cache afterward.
- Source installs use
sentence-transformersfor local embeddings. - Frozen app builds use Chroma ONNX for local embeddings.
- In the current standalone build, only
all-MiniLM-L6-v2is supported for free local embeddings. - Standalone app builds also rely on
onnxruntimeandtiktoken, which are listed inrequirements.txt. - Frozen app builds download the ONNX local embedding model into
<app_data_dir>/models/chroma/onnx_models/on first use.
- Create and activate a virtual environment
python3 -m venv .venv- macOS/Linux:
source .venv/bin/activate - Windows:
.venv\Scripts\activate
- Install dependencies and the package
pip install -r requirements.txtpip install -e .
The editable install is recommended because this repository uses a src/
layout. Without it, python -m uacragent will not resolve unless you
manually set PYTHONPATH=src.
The repository also includes PyInstaller spec files for building standalone desktop app distributions:
- macOS:
UACRAgent_mac.spec - Windows:
UACRAgent_win.spec
Typical build setup:
- Install the normal project dependencies first.
- Install PyInstaller separately:
pip install pyinstaller- if you build with Python 3.10, also install
tomli
Typical build commands:
- macOS:
pyinstaller UACRAgent_mac.spec - Windows:
pyinstaller UACRAgent_win.spec
Expected outputs:
- macOS:
dist/UACRAgent.app - Windows:
dist/UACRAgent/containingUACRAgent.exeand bundled files
Build note:
- Frozen standalone builds use the ONNX local embedding path rather than the
sentence-transformers/ PyTorch stack for packaging reliability.
Create a .env file (copy from .env.sample) and set the provider key(s) you
want to use:
GOOGLE_API_KEY=your-google-api-key-here
# OPENAI_API_KEY=your-openai-api-key-here
# DEEPSEEK_API_KEY=your-deepseek-api-key-here.env lookup behavior by interface:
- Desktop GUI: reads
<app_data_dir>/.envfirst, then falls back to the current working directory.env. - CLI: reads
<app_data_dir>/.envfirst, then falls back to the current working directory.env. - API server: currently reads the current working directory
.env.
For the default app data directory, <app_data_dir> is ~/.uacragent/ unless
you changed it in the desktop app settings.
Recommended locations:
- Desktop GUI / CLI: put
.envin<app_data_dir>/if you want the app to find the same keys regardless of the directory you launch it from. - API server: put
.envin the server's current working directory.
Official API platform / key-management pages:
- OpenAI: platform.openai.com
- Gemini / Google AI Studio: aistudio.google.com
- DeepSeek: platform.deepseek.com
Desktop GUI users can also enter keys directly in the settings window at runtime. Keys entered there are kept in process memory only and are not written to session files.
Provider behavior:
geminiusesGOOGLE_API_KEYopenaiusesOPENAI_API_KEYdeepseekusesDEEPSEEK_API_KEY
Embedding configuration:
EMBEDDING_PROVIDER=geminiusesGOOGLE_API_KEYEMBEDDING_PROVIDER=openaiusesOPENAI_API_KEYEMBEDDING_PROVIDER=localuses a local on-device embedding backend with no API key
For local embeddings, you can choose the downloaded model with
LOCAL_EMBEDDING_MODEL in source installs. Frozen app builds currently support
only one built-app local model:
all-MiniLM-L6-v2uses the built-in ONNX backend, downloaded into<app_data_dir>/models/chroma/onnx_models/
Security note: API key fields are excluded from
Settingsrepr output, and the desktop session persistence layer intentionally does not write API keys to disk.
Startup note:
- The desktop app and API server now log a warning when they detect environment
variable names that look like UACRAgent settings but are misspelled, such as
a typo in
GOOGLE_API_KEYorLLM_PROVIDER.
Optional overrides (see defaults in src/uacragent/infra/settings.py):
LLM_PROVIDER=gemini
LLM_MODEL=gemini-2.5-flash
EMBEDDING_PROVIDER=gemini
EMBEDDING_MODEL=gemini-embedding-001
LOCAL_EMBEDDING_MODEL=all-MiniLM-L6-v2
RETRIEVER_K=8
RATE_TIER=free
API-only optional hardening:
UACRAGENT_ALLOWED_BASE_DIR=/absolute/path/that/api/uploads/must/live/underWhen UACRAGENT_ALLOWED_BASE_DIR is set, the FastAPI server rejects any
requested source file path outside that directory tree.
Sections are written sequentially (one at a time) to avoid overwhelming the
API. The app now uses a named RATE_TIER by default, which maps to concrete
delay/retry settings:
| Tier | Delay | Retries | Base Retry Delay | Typical Use |
|---|---|---|---|---|
free |
6.0 |
4 |
20.0 |
Free and trial plans |
standard |
0.5 |
3 |
8.0 |
Entry paid plans |
pro |
0.1 |
2 |
3.0 |
Higher paid tiers |
unlimited |
0.0 |
1 |
2.0 |
Very high-capacity plans |
If you prefer raw numeric overrides, clear RATE_TIER and then set
LLM_REQUEST_DELAY, LLM_MAX_RETRIES, and LLM_RETRY_BASE_DELAY directly.
Current raw-setting defaults:
| Variable | Default | Description |
|---|---|---|
LLM_REQUEST_DELAY |
6.0 |
Seconds to wait after each LLM call completes before starting the next |
LLM_MAX_RETRIES |
3 |
Max retry attempts on transient 503/429/quota errors (keep low — retries generate more requests) |
LLM_RETRY_BASE_DELAY |
15.0 |
Initial backoff delay in seconds before the first retry (doubles each attempt, capped at 60 s) |
Note: these raw values are only effective when RATE_TIER is explicitly cleared
(RATE_TIER=). When RATE_TIER is set to a named tier (the default is free),
the tier's own values take precedence — for example, free sets LLM_MAX_RETRIES
to 4, not the raw default of 3.
python -m uacragent --guipython -m uacragent(launches the GUI when no file arguments are given)python -m uacragent.ui.desktop.app
The GUI lets you:
- Create, rename, delete, and reopen persistent study sessions
- Choose an LLM provider (
gemini,openai, ordeepseek) and model per session - Choose an API plan tier (
Free,Standard,Pro,Unlimited) to match provider rate limits - Enter provider API keys in the settings dialog when they are not already set in
.env - Choose an embedding provider (
gemini,openai, or free local embeddings`) - Pick a free local embedding model when using on-device embeddings in a source install
- Enter a course name and optional course details
- Add files to different document type categories (Syllabus, Lecture Notes, etc.)
- Search and filter saved sessions from the sidebar search bar
- Choose exam settings and export format
- Choose per-message effort level (
low,medium,high) for chat and generated outputs - Choose a generation reasoning mode in chat:
Quick Reviewfor faster single-pass output orDeep Analysisfor topic extraction plus critic refinement on generated study documents - Pick a custom workspace folder before the first Apply, or let the app auto-create one
- Use Apply to commit setting changes and re-index with the updated session configuration
- Chat with the assistant about the course material
- Toggle provider-backed web search for the next message when supported by the active provider
- Attach supported files to chat messages, including drag-and-drop onto the chat area when desktop drag-and-drop support is available
- Use quick actions to generate a Review Summary, Practice Booklet, Mock Exam, or Exam Prediction
- Open generated outputs directly from the chat transcript
- Cancel an in-flight indexing or chat request from the main panel
- Open global app settings to change color mode, font size, language (
Auto,en, orzh_CN), and the shared app data directory (see Changing the App Data Folder before doing so) - Use the selected desktop language to steer assistant replies and generated document headings in English or Simplified Chinese
- Review the first-launch privacy notice and reopen it later from App Settings when needed
Works on macOS, Windows, and Linux.
Desktop note:
- File drag-and-drop in the chat area uses
tkinterdnd2when the Tk extension is available. The desktop app still works without it; only drag-and-drop is disabled in that case. - The desktop chat pane currently exposes both depth controls:
effort levelchanges retrieval/context size for each turn, whilereasoning modechanges the document-generation pipeline used after a chat-triggered quick action.
When you reopen an existing desktop session from the sidebar, the app first tries a fast attach path. If the saved Chroma index and indexed-file manifest still match the current file set, it reuses the existing retriever without re-embedding or making new embedding API calls. A full re-index runs when the files changed, the index is missing, or you click Apply to force current settings to take effect. On this fast path the session becomes ready silently, without adding a new "documents indexed" notice to the chat transcript.
For most users, the desktop GUI is the easiest way to use the project.
- Launch the app with
python -m uacragent --guior simplypython -m uacragent. - Read and accept the privacy notice shown on first launch.
- Create a new session from the left sidebar.
- Open Settings.
- Enter a Course Name. This is the only required course field.
- Choose your LLM provider and model.
- Add the matching API key in the settings dialog if it is not already loaded
from
.env. For repeat desktop use, placing.envin<app_data_dir>/is usually the most convenient setup. - Review the provider privacy reminder in Settings if you are working with sensitive course material.
- Choose an embedding provider:
geminioropenaiif you want cloud embeddingslocalif you want free on-device embeddings- in source installs,
localusessentence-transformers - in frozen app builds,
localsupportsall-MiniLM-L6-v2via the ONNX local path
- Add course files into the appropriate document buckets:
- syllabus
- lecture notes
- textbook
- assignment
- past exam
- other
- Optionally fill in:
- university / major / course code / professor / semester
- exam type / exam format / exam duration
- extra instructions
- exam information sheet file
- export format
- Optionally choose a custom workspace folder before the first Apply.
- Click Apply.
What Apply does:
- commits the current session settings
- locks in the workspace folder for that session
- saves the session to disk
- copies uploaded files into the session workspace when needed
- keeps the exam info sheet self-contained inside the workspace and removes old copied exam-info files when that field is changed or cleared later
- builds or refreshes the Chroma index
- makes the current provider / embedding / model settings take effect
After indexing finishes, you can use the session in two main ways:
- Ask normal study questions in chat, for example:
Explain the most important topics from these lecture notes.What should I focus on for the final?Summarize the difference between DFS and BFS from the uploaded materials.
- Generate study documents either:
- by pressing a quick-action button, or
- by asking naturally in chat, for example
Generate a review summary for this course.
Useful desktop controls:
Effort levelchanges retrieval/context depth for each turn.Reasoning modechanges the generation pipeline depth for study-document tasks.Web searchis only available for providers that support it.File attachmentsare available only when the active provider/model supports file inputs. Unsupported image/file uploads are disabled in the UI.Cancelstops an in-flight indexing or chat task.Languagein App Settings supportsAuto, English, and Simplified Chinese.
Reopening sessions:
- Reopen a saved session from the sidebar.
- If the file set and saved Chroma index still match, the app reuses the existing retriever without re-embedding.
- If files changed, or you click Apply, the app performs a full re-index.
- Put files into the most accurate document type bucket you can. Retrieval quality is better when syllabi, lecture notes, assignments, and past exams are separated correctly.
- Add past exams when available. The weighted retriever gives them more influence for exam-oriented tasks.
- Use
Quick Reviewwhen you want faster, cheaper output. - Use
Deep Analysiswhen quality matters more than latency or token cost. - Use local embeddings if you want to reduce cloud costs.
- Reuse the same session for the same course so the app can reuse the saved index and chat history.
The CLI is an interactive terminal assistant, not a one-shot generator.
- Install the package with
pip install -e .. - Set your provider key(s) in
<app_data_dir>/.env,cwd/.env, or your shell environment. The CLI checks<app_data_dir>/.envfirst. - Start the CLI with one or more course files and a course name. Supported inputs include PDF, DOCX, CSV, and common text/code formats.
- Wait for startup indexing to finish.
- Ask questions or request generated study documents in natural language.
- Exit with
exit,quit,Ctrl-C, orCtrl-D.
Example:
python -m uacragent outline.pdf lecture1.pdf lecture2.pdf \
--course-name "Introduction to Algorithms" \
--doc-type lecture_note \
--exam-type final \
--exam-format written \
--effort-level medium \
--workspace-id algo-finalCLI behavior to remember:
- All positional files are treated as the same
--doc-typewhen you provide one. - If you omit
--doc-type, all input files are treated asother. - The CLI reuses the same workspace when you reuse
--workspace-id. - The CLI currently exposes
effort_levelonly, not the desktop reasoning-mode toggle.
The FastAPI layer is the programmatic one-shot generation interface.
- Start the server with
uvicorn uacragent.api.main:app --reload. The API currently reads.envfrom the server's current working directory. - Prepare a JSON body with:
classified_filescourse_name- optional exam/course metadata
task_type- optional
effort_level - optional
reasoning_mode - absolute file paths for every source document
- Send a
POST /reviewrequest. - Read the returned plan plus the saved markdown path.
Use the API when you want to integrate generation into another app, script, or service. Use the desktop GUI when you want persistent sessions, interactive study chat, and richer controls.
The desktop app persists session state so you can return to previous work.
- Bootstrap config:
~/.uacragent/config.json - Default app data directory:
~/.uacragent/ - Session index:
<app_data_dir>/index.json - Local embedding model cache:
<app_data_dir>/models/ - Auto-created workspaces:
<app_data_dir>/sessions/<workspace_id>/ - Per-session agent bundle:
<workspace>/.uacragent/ - Per-session state file:
<workspace>/.uacragent/session.json
Persisted session data includes course settings, selected files, chosen provider/model, chat history, and session UI extras such as export format and embedding selection. App-level appearance preferences (color mode, font size, language) are stored separately in the bootstrap config. API keys are not saved.
Notes:
- New sessions get a unique autogenerated
workspace_id, so auto-created workspaces do not collide with each other. - The app data directory can be changed from the session-list pane’s global app settings button and takes full effect after restarting the app.
- Global appearance settings are persisted in the bootstrap config and include
light/dark mode, small/medium/large font size, and
Auto/en/zh_CNUI language. - Local embedding models are cached under
<app_data_dir>/models/, including the frozen app’s ONNX backend under<app_data_dir>/models/chroma/onnx_models/. - Desktop and API logs are written under
<app_data_dir>/logs/uacragent.log. - All agent-generated files inside a workspace are grouped under
<workspace>/.uacragent/so they stay separate from the user’s own files. - Once a session has been created and its workspace committed, that workspace is treated as fixed for the lifetime of the session.
- Deleting a session removes the
<workspace>/.uacragent/bundle. Original source files outside that folder are not affected. For auto-created workspaces (those under<app_data_dir>/sessions/), the workspace folder itself is also removed when it contains no other files after the bundle is deleted.
The app data folder can be changed in App Settings. Before doing so, read the following carefully:
Sessions are not migrated. Changing the folder does not move any existing data. Sessions created under the old folder remain there and will not appear in the session list until you switch back. If you want to continue using existing sessions, switch back to the original folder in App Settings.
Do not point the app at a folder that already contains unrelated files. The app writes its own files (index.json, session workspaces, model cache, logs) directly into the chosen folder. Using a folder that already contains your own documents or other application data risks name collisions and makes the app’s files harder to identify and manage.
Recommended practice:
- Use a dedicated, initially empty folder as the app data directory.
- If you need to relocate your data, manually copy the entire old app data folder to the new location first, then point the app at the new path.
- If you change the folder by mistake, switch back immediately in App Settings — the original folder and its sessions are still intact.
--course-name is required for CLI runs with input files.
The CLI examples below assume you completed pip install -e . during setup.
The CLI uses the provider configured through LLM_PROVIDER/LLM_MODEL and the
matching API key from your environment.
--workspace-id controls the workspace folder name under the app data
directory. Reusing the same ID lets the CLI reuse the same persisted Chroma
store and outputs for unchanged files, which can avoid re-embedding work and
additional embedding API calls on later runs.
CLI runs also respect EMBEDDING_PROVIDER. For example, you can use DeepSeek
for chat/generation together with EMBEDDING_PROVIDER=local to avoid cloud
embedding costs.
The CLI also supports --effort-level low|medium|high to control retrieval
depth for each chat turn and generated document request.
The current CLI does not expose the desktop-only Quick Review / Deep Analysis reasoning-mode toggle. Generated documents from the CLI use the
default quick reasoning pipeline.
How the current CLI works:
- It indexes the supplied files at startup, or reuses the existing workspace index when the file set is unchanged.
- It shows live progress updates while indexing documents and generating study documents.
- It then enters an interactive chat loop in the terminal.
- You can ask course questions or request a generated document in natural language.
- Generated outputs are saved to the workspace and their paths are printed in the terminal.
Start an interactive CLI session with course files:
python -m uacragent outline.pdf lecture.pdf \
--course-name "Introduction to Algorithms" \
--exam-format written \
--effort-level mediumUse explicit document typing for all supplied files:
python -m uacragent syllabus.pdf \
--course-name "Data Structures" \
--doc-type syllabus \
--exam-type final \
--exam-format mixed \
--university-name "University of Toronto" \
--major "Computer Science" \
--course-code "CSC263" \
--professor-name "Dr. Smith" \
--semester "Fall 2024" \
--exam-duration "2 hours" \
--workspace-id csc263-finalOnce the CLI starts, you can type requests such as:
Explain the main topics covered in these notes.Generate a review summary for this course.Generate a practice booklet for this course.Generate a mock exam for this course.Generate an exam prediction for this course.
To leave the terminal chat, type exit or press Ctrl-C / Ctrl-D.
app.py is no longer the main interactive entrypoint. It is a small
repo-level helper that exposes main() / main_simple() for direct import and
prints guidance to use python -m uacragent if run as a script.
Start the server:
uvicorn uacragent.api.main:app --reload
The API also uses the provider configured through LLM_PROVIDER/LLM_MODEL
and the matching API key from the environment.
workspace_id in API requests resolves to a folder under the app data
directory in the same way as the CLI.
The API likewise respects EMBEDDING_PROVIDER, EMBEDDING_MODEL, and
LOCAL_EMBEDDING_MODEL in source installs. Frozen app builds use the ONNX
local embedding path instead:
all-MiniLM-L6-v2under<app_data_dir>/models/chroma/onnx_models/
copy_to_workspace controls whether uploaded source files are copied into the
workspace's .uacragent/uploads/ bundle during API generation. Leave it at
true for the normal self-contained workspace behavior.
Security note:
- Without
UACRAGENT_ALLOWED_BASE_DIR, the API accepts any absolute existing file path on the host machine. - The current API is intended for local trusted use, not public or multi-user deployment.
- If you want an extra local safety boundary, set
UACRAGENT_ALLOWED_BASE_DIRto restrict file access to a trusted directory tree.
API file-path rules:
- every file path in
classified_filesmust be absolute - the path must point to an existing regular file
- if
UACRAGENT_ALLOWED_BASE_DIRis set, the file must resolve under that directory
The API exposes both depth controls:
effort_levelcontrols retrieval/context depthreasoning_modecontrols generation pipeline depth (quickordeep)
Endpoints:
GET /health— health checkPOST /review— generate output with classified documents:{ "classified_files": { "syllabus": ["path/to/syllabus.pdf"], "lecture_note": ["path/to/notes.pdf"], "past_exam": ["path/to/exam1.pdf"] }, "course_name": "Introduction to Algorithms", "exam_format": "written", "exam_type": "final", "task_type": "review_summary", "extra_instructions": "", "effort_level": "medium", "reasoning_mode": "quick", "workspace_id": "default", "copy_to_workspace": true, "university_name": "University of Toronto", "major": "Computer Science", "course_code": "CSC263", "professor_name": "Dr. Smith", "semester": "Fall 2024", "exam_duration": "2 hours", "exam_info": "Closed book. One formula sheet allowed." }
course_name is required in the review request. effort_level is optional and
accepts low, medium, or high. reasoning_mode is optional and accepts
quick or deep. All other fields (university_name, major,
course_code, professor_name, semester, exam_duration, exam_info) are
optional.
- Canonical output is written to
<workspace>/.uacragent/outputs/review_<timestamp>.md - When using the desktop GUI, optional DOCX/PDF exports are written to the same output folder
- Uploaded file copies are organized under
<workspace>/.uacragent/uploads/<doc_type>/ - Vector DB is persisted under
<workspace>/.uacragent/chroma_db/ - The generated document header includes all provided course information fields
Workspace resolution:
- Desktop GUI with a custom workspace folder:
<workspace>is the chosen folder - Desktop GUI with auto workspace:
<workspace>is<app_data_dir>/sessions/<workspace_id>/ - CLI / API:
<workspace>is<app_data_dir>/<workspace_id>/
src/uacragent/
__main__.py Interactive CLI + desktop GUI entry point
agent/
service.py High-level orchestrator (AgentService)
conversation.py Conversational agent for session-based chat + task triggering
session.py Session state container for chat, files, and preferences
pipeline.py RAG pipeline with task-type dispatch
reasoning.py Reasoning-mode configuration, topic extraction, and critic/refinement passes
workspace_manager.py Workspace cleanup helpers for Apply / re-index flows
prompts/
_prompts.py Shared prompt-directory path + language-steering helpers
conversation_system.md System prompt for desktop chat sessions
review_summary_planner.md Review summary planner
review_summary_writer.md Review summary writer
practice_booklet_planner.md Practice booklet planner
practice_booklet_writer.md Practice booklet writer
mock_exam_planner.md Mock exam planner
mock_exam_writer.md Mock exam writer
exam_prediction_planner.md Exam prediction planner
exam_prediction_writer.md Exam prediction analysis writer (Part A)
exam_prediction_paper_writer.md Predicted exam paper writer (Part B)
topic_extraction.md Deep-analysis topic extraction prompt
section_critic.md Deep-analysis refinement / critic prompt
api/
main.py FastAPI application factory
routes.py API endpoints (/health, /review)
schemas.py Request / response models (enum-validated fields)
deps.py Dependency injection (settings, service singletons)
domain/
models.py Core data models (ReviewPlan, SectionSpec)
errors.py Custom exception hierarchy
providers.py Provider metadata, labels, and env-var mapping
doc_priorities.py Task-aware document weighting presets for retrieval
rate_tiers.py API plan tier presets for request pacing
types.py Enums (DocumentType, ExamFormat, ExamType, TaskType, ExportFormat)
infra/
settings.py Pydantic-based configuration (.env)
loaders.py Document loading with multi-stage type-specific splitting, including CSV table ingestion
vectorstore.py Chroma vector store, manifest tracking, and weighted retriever
llm.py Provider-aware LLM client wrapper (Gemini / OpenAI / DeepSeek)
auth.py Provider-specific API key validation
persistence.py Desktop session persistence, app-data config, and local model cache management
workspace.py Workspace directory management with classified folders
export/
markdown.py Markdown export
docx.py DOCX export (python-docx)
pdf.py PDF export (fpdf2, Unicode font auto-detection)
ui/
desktop/
app.py Tkinter desktop entrypoint that composes the GUI mixins
_custom_widgets.py Shared custom widgets for rounded chips, session list, and sidebar controls
_ui_constants.py Shared UI strings, themes, OS helpers, and i18n tables
_appearance_mixin.py Theme, font-size, language, and App Settings logic
_settings_mixin.py Session Settings dialog and validation flow
_session_mixin.py Session list management and persistence hooks
_chat_mixin.py Chat send/receive flow, indexing, and output-link UI
assets/
UACRAgent.icns macOS app-bundle icon asset
logo_icns_source.png Source PNG used to generate the macOS ICNS asset
logo_*.png/svg/ico Desktop and package icon variants
tests/
test_domain.py Domain model and enum tests
test_export.py Markdown / DOCX / PDF export tests
test_loaders.py Document loading and splitting tests
test_pipeline_utils.py Pipeline utility function tests
test_workspace.py Workspace path and directory tests
app.py Lightweight importable helper for direct service calls
.env.sample Example environment configuration
UACRAgent_mac.spec PyInstaller spec for macOS standalone builds
UACRAgent_win.spec PyInstaller spec for Windows standalone builds
LICENSE MIT license text
Thanks to the volunteer test users who helped exercise the desktop assistant, retrieval flow, workspace handling, and study-support UX during development. Their feedback helped make this agent better.
- Test-user credits will be listed here once they are confirmed for public acknowledgement.