Project Hub - Technical Details
Structure and data storage of Project Hub: MCP server, SQLite data model, folder layout, note files and their synchronization, attachments, export and import, HTML reports.
Project Hub - Technical Details
Structure
| Component | Description |
|---|---|
| Skills | Markdown instructions under skills/ that Claude executes as slash commands |
| MCP server | Python process project-hub-mcp (stdio), started through bin/run-server with the Python from ~/.project-hub/venv |
| Database | SQLite file, by default ~/.project-hub/project-hub.db |
| Files | Markdown notes and attachments under docs_root, knowledge documents under knowledge_root |
The plugin defines no hooks. The server initializes the database at startup and adds missing tables and columns itself.
Directories
~/.project-hub/
βββ config.yaml
βββ project-hub.db (plus -wal and -shm while running)
βββ venv/
βββ knowledge/<project-type>/*.md
βββ project-types/<type>/ custom project types
βββ reports/ HTML reports
βββ exports/ JSON exports
{docs_root}/<project-slug>/docs/
βββ emails/
βββ meeting-notes/
βββ misc/
βββ attachments/
Data model
| Table | Content |
|---|---|
projects |
Slug (unique), name, type, status, description, market, products, phase, go-live, budget, notes, docs path, timestamps |
contacts |
Project, name, role, type (internal or external), email, phone, company, notes, is_shared |
notes |
Project, title, type, content, agenda, attachments (JSON list), file path, timestamps |
project_links |
Links between two projects |
session |
exactly one row: active project and last used skill |
- The slug is derived from the project name (lowercase, hyphens). Two names with the same slug are not possible.
- Deleting a project also removes its contacts, notes and links. Shared contacts are reassigned to another project first.
- The database stores links only as
successororrelated.predecessoris the reverse view of asuccessor. - The session row is global. It applies to every Claude session that uses the same database.
Notes: database and file
When a note is created, the server writes the text to the database and also as a Markdown file in the project's docs folder:
| Note type | Target folder | File |
|---|---|---|
meeting-notes |
meeting-notes/ |
<date>-<title-slug>.md |
email |
emails/ |
<date>-<title-slug>.md |
decision, note |
misc/ |
<date>-<title-slug>.md |
action-item |
misc/ |
entry in the shared file todo.md under "Open" |
The database is the authoritative source:
- Changes made through
tool_update_note(and thusedit-note) write to the database only. The Markdown file keeps the old title, content and subfolder. - Deleting a note removes its file, except for
action-item, becausetodo.mdholds several tasks. - The file name is derived from target folder, date and title slug, not from the note type. Two notes with the same title on the same day land in the same folder and overwrite each other even if their types differ: a
noteand adecisionsharemisc/. The title slug is truncated to 50 characters, so different long titles with the same beginning can collide as well. In all cases the database keeps both notes. A date or a distinguishing prefix at the start of the title avoids this. - Reports, search and skills read from the database, not from the files.
Attachments
- The copy lives under
{docs_root}/<slug>/docs/attachments/. The original stays untouched. - The attachment is stored as a JSON entry with name, path and size on the note.
- When a note is deleted, its attachment files remain in the folder.
tool_add_notewithsource_pathspreserves the originals in the same call, so referenced files are not lost.
Export and import
An export (compose export) is a JSON file with the project, contacts, notes and links (links by the other project's slug).
- Attachment files and note Markdown files are not part of the export.
- The note rows contain the attachments field unchanged, so its entries refer to paths on the source machine.
- An import creates a new docs folder. It restores links only if the linked project already exists in the target database, otherwise they are listed as not restored.
renameappends a timestamp to the slug.overwritedeletes the existing project completely, including its docs folder with note Markdown files and attachments on disk, and recreates it.
HTML reports
The report is a single HTML file rendered from a Jinja2 template. When opened in a browser, the file loads its chart library (Chart.js) from cdn.jsdelivr.net. Without an internet connection this library is missing. Labels are in German. The "Offene Aufgaben" (open tasks) section contains all notes of type action-item, without a completion filter.
Search
Search is a simple substring search (SQL LIKE) without an index and without ranking. Case is ignored for ASCII letters only, umlauts are compared exactly. % and _ in the search term act as wildcards. Notes are returned newest first, contacts sorted by name.