Contributing¶
Getting set up¶
Follow the setup guide to get a development instance running. The short version:
git clone https://github.com/yourname/yapflows.git
cd yapflows
make install
make dev
make dev starts both the backend (port 8000) and the frontend (port 3000) with live reload. Backend changes reload automatically via Uvicorn's --reload flag. Frontend changes are picked up by Next.js.
Make targets¶
| Command | What it does |
|---|---|
make install |
Install Python + Node dependencies |
make dev |
Start backend + frontend concurrently with live reload |
make test |
Run backend tests with pytest |
make build |
Build the frontend for production |
make start |
Serve the production build (frontend served by the backend) |
make kill |
Kill processes on ports 8000 and 3000 |
make clean |
Remove build artifacts and caches |
make venv |
Create the Python virtual environment only |
make docs |
Preview the documentation site locally |
Running tests¶
make test
Tests live in backend/tests/. The test suite uses pytest and pytest-asyncio. Most tests are unit tests of individual domain objects — no running server required.
The test design philosophy: every domain class receives its dependencies via __init__, so tests inject mock or in-memory dependencies directly. No patching, no complex fixtures.
Key test utilities available:
MockProvider— returns scripted responses without any I/O or network callsMemorySessionStore— in-memory session storage with no disk accessConfig(base_dir=tmp_path)— isolated config pointing to a temporary directory
Project structure¶
yapflows/
├── backend/
│ ├── src/
│ │ ├── core/ Domain model (Agent, Session, Task, Trigger, Skill, events)
│ │ ├── providers/ Provider implementations (ClaudeCliProvider, OpenRouterProvider)
│ │ ├── service/ Business logic (scheduler, queue, memory assembly, triggers)
│ │ ├── api/ FastAPI routes and WebSocket handlers
│ │ └── tools/ Strands @tool functions (bash, browser — OpenRouter only)
│ ├── agents/ Built-in agent definitions
│ ├── skills/ Built-in skill definitions
│ ├── environments/ Built-in environment presets
│ └── tests/
└── frontend/
├── app/ Next.js App Router pages
├── components/ React components
├── hooks/ Custom React hooks
└── lib/ Utilities (API client, keyboard shortcuts, types)
See Architecture for a detailed explanation of each layer.
Adding a new provider¶
- Create
backend/src/providers/{name}.py - Implement
BaseProvider— defineprovider_idandasync def run(...) -> AsyncIterator[Event] - Register the provider in the provider factory
- Add a built-in environment in
backend/environments/{id}.jsonwithprovider_idset to your new provider's ID - Write tests using
MockProvideras a reference for what the interface should return
The rest of the system — sessions, tasks, triggers, the frontend — requires no changes. Provider is resolved by ID at session creation time.
Adding a new built-in agent¶
Create a markdown file at backend/agents/{name}.md with YAML front matter (at minimum provider and model). It will appear in the Agents tab for all users as a built-in agent.
Adding a new built-in skill¶
Create a directory at backend/skills/{name}/ with a skill.md file. It will appear in the Skills tab and be listed in every agent's system prompt automatically.
Frontend development¶
The frontend is a Next.js app using the App Router. Each section of the app has its own page component in frontend/app/{section}/page.tsx.
Shared components live in frontend/components/shared/. These are the building blocks used across all tabs:
TwoPaneLayout— split list/detail layoutSidebarPanel— standardised left panel with refresh and create buttonsItemList— generic selectable list with keyboard navigation and URL syncMarkdownEditor— markdown view/edit with saveEmptyState— shown when a list is empty or nothing is selected
Follow the existing patterns when adding a new tab or section. Every tab uses TwoPaneLayout and SidebarPanel.
Logging¶
Use the named logger for your module — logging.getLogger(__name__). This keeps log output consistent with the [component] column format.
Log at INFO for significant events (session created, task fired, run completed). Use DEBUG for high-frequency or low-level events (text chunks, memory reads). Always include exc_info=True on error logs so the traceback is captured.
See Configuration for log format details and the log file location.