FocusPilot is a small MVP that turns a free-form goal into actionable tasks with AI. The app keeps the flow intentionally simple: write a goal, break it down, review tasks, and see the top tasks to focus on today.
Many people know what they want to achieve, but they get stuck when the goal is still too broad or mentally heavy. A goal like "build my portfolio", "plan my thesis week", or "launch a restaurant app" is understandable, but not immediately actionable.
FocusPilot reduces that friction by turning one messy objective into a short list of concrete tasks. Instead of forcing the user to manually plan everything from scratch, the app helps answer:
- What should I do first?
- What are the next realistic steps?
- Which tasks matter most today?
This makes the app useful for users who struggle with overwhelm, unclear priorities, or the gap between intention and execution.
- Frontend: React + Vite + TypeScript
- Backend: FastAPI + Python 3.12
- Database: SQLite
- ORM: SQLAlchemy
- AI: OpenAI API with
OPENAI_API_KEY, plus a safe mock fallback
focus-pilot/
├── backend/
│ ├── app/
│ │ ├── api/
│ │ ├── core/
│ │ ├── db/
│ │ ├── models/
│ │ ├── schemas/
│ │ └── services/
│ ├── tests/
│ ├── .env.example
│ └── requirements.txt
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ └── lib/
│ └── package.json
└── README.md
cd backend
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
copy .env.example .env
uvicorn app.main:app --reloadBackend runs on http://127.0.0.1:8000.
cd frontend
npm install
npm run devFrontend runs on http://127.0.0.1:5173.
If your backend uses a different URL, set:
set VITE_API_URL=http://127.0.0.1:8000- If
OPENAI_API_KEYexists, the backend calls OpenAI fromapp/services/ai_service.py. - The model receives a system prompt that asks it to convert one goal into a small set of specific tasks.
- The backend uses structured outputs through the OpenAI
Responses APIand parses the answer into a typed Pydantic model. - Each generated task must include
title,description,priority,effort_minutes, andcategory. - The response is validated before saving tasks.
- If the first response is cut off because of token limits, the backend retries with a larger output budget.
- If the key is missing, the API uses a mock task generator so the app still works.
The AI flow lives in backend/app/services/ai_service.py and is designed to be narrow and predictable:
- The frontend sends a goal to
POST /goals. - The backend stores the goal in SQLite.
- The frontend then calls
POST /goals/{id}/decompose. - The backend sends the goal text to OpenAI with instructions to generate a limited list of actionable sub-tasks.
- OpenAI returns structured data that is parsed into the
AIResponseschema. - The backend normalizes the result and saves each task in the database.
- The frontend fetches the saved tasks and displays them in order, hiding completed ones by default.
This design keeps the model focused on one responsibility: decomposition. The app does not let the model write directly to the database or decide UI behavior. Instead, the backend validates and normalizes the output first, which reduces fragile AI behavior and makes the system easier to debug.
POST /goalsPOST /goals/{id}/decomposeGET /tasksPATCH /tasks/{id}GET /plan/todayGET /health
cd backend
pytestapp/main.pywires the FastAPI app and creates SQLite tables on startup.app/api/routes.pykeeps the HTTP layer small and focused on orchestration.app/services/ai_service.pyowns prompt design, OpenAI calls, JSON validation, and fallback behavior.app/models/andapp/schemas/separate persistence from API validation.- The frontend is a single-page React app with a small fetch wrapper and a minimal component split.
- Prevent duplicate decompositions per goal or add a "regenerate tasks" flow.
- Add filtering by goal and a simple goal history view.
- Introduce optimistic UI updates and a small loading skeleton for a smoother UX.