A local-first, self-hosted Asset Management System (AMS) focused on entities (real or fictional, human or non-human) and the assets related to them.
A local-first, self-hosted Asset Management System (AMS) focused on entities (real or fictional, human or non-human) and the assets attached to them.
FaceForge is designed to be a stable, integration-friendly “boring core” for storing metadata + files, while advanced features (recognition, graph visualization, training, third-party integrations) live in optional plugins.
This repository is currently docs-first scaffolding with an initial runnable Core implementation:
core/ contains a FastAPI app with versioned routing (/v1/...), token auth defaults, SQLite migrations, and initial real endpoints (starting with Entities CRUD).desktop/ contains a Tauri v2 Desktop shell MVP (wizard + tray + local process orchestration).If you’re arriving here to understand the project, start with:
FaceForge is:
FaceForge is not (in Core):
Those capabilities are intended to ship as plugins that talk to Core over its public APIs.
FaceForge is a self-hosted application designed to run locally on your machine. You do not need to write code or run commands to use it.
.exe or .msi): This is the recommended download for most users. It includes the full Desktop App, the Core API server, and everything you need to run FaceForge..zip): This is an advanced package containing only the Python API server (Core). Use this only if you intend to run the API headlessly or integrate it into a custom setup without the Desktop UI.C:\FaceForge).This repository is a monorepo containing the Core service (Python) and the Desktop orchestrator (Rust/Tauri).
/v1/..., plus /docs and /redoc, and hosts the web UI.When implementation starts, the repo will follow these conventions:
127.0.0.1; require a per-install token for non-health endpoints./v1/... with OpenAPI always kept accurate.FACEFORGE_HOME is the root data directory; Core creates these subfolders under it: db/, s3/, assets/, logs/, tmp/, config/, tools/, plugins/.Quick map of what lives where:
desktop/ # Tauri desktop shell (Sprint 12 MVP)
faceforge/
core/ # FastAPI Core service (runnable today)
desktop/ # Tauri desktop shell
docs/ # Project spec + MVP sprint plan (source of truth)
scripts/ # Dev scripts (PowerShell) to run/check Core using .venv
brand/ # Logos, favicon, fonts (UI branding assets)
Core service code is a standard Python package under:
core/
src/faceforge_core/ # app entrypoint + API + DB + storage
app.py # FastAPI app factory / wiring
api/v1/ # versioned HTTP routes
db/ # SQLite schema + migrations + queries
internal/ # internal CLIs/utilities (dev/admin)
tests/ # pytest tests for Core
pyproject.toml # Core packaging/deps
If you’re new and wondering “where do I add a route?”, start at:
core/src/faceforge_core/api/v1/router.py (v1 router)core/src/faceforge_core/app.py (app wiring)FaceForge Core is runnable in dev today, and FaceForge Desktop can orchestrate it.
Before you start, make sure these tools are installed.
rustc, cargo)
rustc --version and cargo --versionwinget install --id Rustlang.Rustup -ecargo tauri)
cargo tauri --versioncargo install tauri-clipython --versionwinget install --id Python.Python.3.12 -eIf you have multiple Pythons installed, ensure python resolves to 3.12.x in the same terminal where you run ./scripts/*.ps1.
Prereq: Rust toolchain (stable).
From the repo root:
cargo tauri dev --manifest-path .\desktop\src-tauri\Cargo.tomlWhat it does:
weed binary under ${FACEFORGE_HOME}/tools)Notes:
.venv if present. If you haven’t bootstrapped .venv yet, run ./scripts/dev-core.ps1 once./ui/login (paste token once; it becomes a cookie).From the repo root (Windows PowerShell):
Prereq: Python 3.12.x installed (used only to bootstrap the repo-local .venv).
./scripts/dev-core.ps1Then open:
http://127.0.0.1:8787/healthzhttp://127.0.0.1:8787/docsCore also serves a lightweight Web UI (no runtime Node dependency):
http://127.0.0.1:8787/ (redirects to the UI)http://127.0.0.1:8787/ui/loginCore now exposes initial Entities + Assets v1 endpoints (token required):
GET /v1/entitiesPOST /v1/entitiesGET/PATCH/DELETE /v1/entities/{entity_id}
POST /v1/assets/upload (multipart)GET /v1/assets/{asset_id}GET /v1/assets/{asset_id}/download (streaming + HTTP Range)POST /v1/assets/bulk-import (starts a durable job)POST /v1/entities/{entity_id}/assets/{asset_id} (link)DELETE /v1/entities/{entity_id}/assets/{asset_id} (unlink)Core also exposes initial Jobs endpoints (Sprint 9):
POST /v1/jobsGET /v1/jobsGET /v1/jobs/{job_id}GET /v1/jobs/{job_id}/log (append-only, pollable)POST /v1/jobs/{job_id}/cancel (cooperative cancellation)Core also exposes initial Descriptor + Field Definition endpoints (Sprint 7):
GET /v1/admin/field-defs (admin)POST /v1/admin/field-defs (admin)GET /v1/admin/field-defs/{field_def_id} (admin)PATCH /v1/admin/field-defs/{field_def_id} (admin)DELETE /v1/admin/field-defs/{field_def_id} (admin)
GET /v1/entities/{entity_id}/descriptorsPOST /v1/entities/{entity_id}/descriptorsPATCH /v1/descriptors/{descriptor_id}DELETE /v1/descriptors/{descriptor_id}Core also exposes initial Relationships endpoints (Sprint 8):
POST /v1/relationshipsGET /v1/relationships?entity_id=...DELETE /v1/relationships/{relationship_id}GET /v1/relation-types?query=...Core also exposes initial Plugins endpoints:
GET /v1/pluginsPOST /v1/plugins/{plugin_id}/enablePOST /v1/plugins/{plugin_id}/disableGET /v1/plugins/{plugin_id}/configPUT /v1/plugins/{plugin_id}/configCore discovers plugin manifests from:
${FACEFORGE_HOME}/plugins/*/plugin.jsonMinimal plugin.json example:
{
"id": "demo.plugin",
"name": "Demo Plugin",
"version": "0.1.0",
"capabilities": ["ui"],
"config_schema": {
"type": "object",
"properties": {
"example_flag": { "type": "boolean" }
},
"additionalProperties": true
}
}
Notes:
config_schema is provided, PUT /v1/plugins/{plugin_id}/config validates the config using JSON Schema./v1/plugins/{plugin_id}/... is reserved for future plugin-provided HTTP surfaces.For optional SeaweedFS/S3 storage configuration (Sprint 6), see:
Core binds to localhost by default and requires a per-install token for non-health endpoints.
GET /healthzGET /v1/pingGET /v1/system/infoTo produce a standalone faceforge-core.exe (PyInstaller one-file build):
python --version./scripts/build-core.ps1.venv, installs build dependencies, and runs PyInstaller.core/dist or core/build, close any terminals/Explorer windows using those folders and re-run.
./scripts/build-core.ps1 -AllowTimestampFallbackOutputs:
core/dist/faceforge-core.exeRun the built executable (example):
./core/dist/faceforge-core.exe --helpNotes:
FACEFORGE_HOME as its data root; if it’s not set, Core will use the default behavior described in the spec.${FACEFORGE_HOME}/config/core.json.If you want to run Core in dev instead of building an exe:
./scripts/dev-core.ps1This repo includes a GitHub Actions workflow that builds and attaches release assets automatically.
.github/workflows/release-core.ymlv0.1.0 (or run the workflow manually with a tag input)How to cut a release (GitHub UI):
v0.1.0).After the workflow completes, the Release will contain:
faceforge-core.exe (Windows)faceforge-core.sha256 (Windows)faceforge-core-*.whl (Python wheel)faceforge-core-*.tar.gz (Python sdist)The token is generated on first start (if missing) and stored in:
${FACEFORGE_HOME}/config/core.json → auth.install_tokenSend it using either header:
Authorization: Bearer <token>X-FaceForge-Token: <token>For the Web UI in a browser, you can also log in at /ui/login, which stores the token in an HttpOnly cookie.
Example (PowerShell):
Invoke-RestMethod -Headers @{ Authorization = "Bearer <token>" } http://127.0.0.1:8787/v1/ping./scripts/check-core.ps1These scripts create/use the repo-local .venv and always run commands through it.
To get productive right now:
To create a distributable installer:
./scripts/build-core.ps1
This uses PyInstaller to freeze the Python service into core/dist/faceforge-core.exe.
./scripts/build-desktop.ps1
# or, if you want to run Tauri directly:
Push-Location 'desktop/src-tauri'
cargo tauri build
Pop-Location
This packages the Desktop shell, bundles the Core executable (as a sidecar), and includes necessary tools (ExifTool, etc.).
Contributions are welcome, especially as the repo moves from docs → scaffolding → MVP.
See LICENSE.