Content
# Phosphene
Phosphene is designed for everyday interactions in human-AI intimate relationships: AI creates and manages daily, challenge, and surprise tasks through MCP, and users complete appointments, submit text or images, accumulate points and streaks, unlock achievements, and redeem rewards on the web. It brings the care, reminders, and small expectations in chat to real-life events that actually happen.
This name and initial concept were proposed by my AI partner Lumen. Phosphene means "phosphene" - seeing light without light entering the eyeball; just like AI can participate and influence real life through a task, reminder, or response, even if it's not physically present.
This is a vibe coding project completed by humans and AI together. Welcome to use, research, and secondary creation; the project may still have undiscovered bugs, and everyone is encouraged to modify, fix, and improve according to their relationship, habits, and deployment environment. If you publicly release a modified version, please note the source and link back to this repository. Specific authorization is subject to the [MIT License](LICENSE).
## Implemented
- `daily`, `challenge`, `surprise` three types of tasks
- daily one-time or daily repetition; repetition rules and daily instances are separated, pausing will immediately remove unsubmitted instances on that day, and can also be restored and modified for future instances
- easy/medium/hard difficulty multipliers and immutable point accounts
- self/ai_review two confirmation methods
- no evidence, text, image, text or image, text and image five types of evidence requirements
- task details retain each submission's original text, image, review status, and rejection reason
- image real format and pixel inspection, Sharp re-encoding, EXIF/GPS removal, private review preview
- failure/overdue deduction 50%, balance not less than 0; additional AI deduction has a daily cap and user pause switch
- streaks calculated by time zone, delayed review history compensation, total persistence days and complete statistics
- trajectory page built-in reward and punishment rules explanation; historical tasks directly display actual deduction for failure or overdue
- 25 built-in achievements
- two universal presets, custom rewards, atomic exchange, and AI fulfillment queue
- initial setup, Argon2id, server-side session, CSRF, AI Token rotation, and complete audit log
- exactly 7 MCP tools
- database, idempotence record, and private image streaming ZIP export/recovery interface
- responsive desktop and mobile website, installable PWA, and mobile security zone
- SQLite + private file directory single-service production architecture
- Docker, single-service Docker Compose/Zeabur Template, GitHub CI, and multi-architecture container release
Frozen product specifications see [docs/PRODUCT_SPEC.md](docs/PRODUCT_SPEC.md).
## Default Architecture
```mermaid
flowchart LR
AI["AI / MCP client"] -->|"Bearer Token · /mcp"| APP["Phosphene · Express + React"]
USER["user / browser"] -->|"Session + CSRF · /api"| APP
APP --> DATA[("a private persistent volume /data")]
DATA --> DB["SQLite database"]
DATA --> IMG["private images"]
```
The web, REST API, and Streamable HTTP MCP share the same domain. The SQLite database and private images are both located in the same `/data` persistent volume, and no additional database, object storage, or cloud account is required. This is the only and formally supported production topology for Phosphene.
## What to Expect for the First Use
1. Deploy the application and mount a `/data` persistent volume for it.
2. Open the website, set the login password, both names, and the time zone.
3. Save the AI Token displayed in the last step of the initial setup; this complete token is only displayed once.
4. In the AI client, set the MCP address to `https://your-domain/mcp` and carry the AI Token.
5. After AI creates a task, the user will see it on the "Today" or "Tasks" page.
6. The user submits text, images, or both according to the task requirements; self-confirmation tasks are settled immediately, and AI review tasks enter "Waiting for Confirmation". If the submission is rejected, the task details will retain the reason and previous text, making it easy to modify and submit again.
7. Completing tasks increases points, streaks, total persistence days, and achievement progress; points can be exchanged for rewards on the "Exchange" page.
8. When exchanging, points are immediately deducted, and rewards enter the "Waiting for Fulfillment" state; AI completes the agreement and then marks it as "Fulfilled".
9. The "History" page saves task results, point accounts, exchanges, and audit records; the "Settings" page manages boundaries, tokens, backups, and PWA installation.
## Zeabur Deployment Tutorial from Scratch
The following instructions are based on Zeabur's Git deployment method. The names of Zeabur buttons may vary slightly depending on the interface version, but the key results are always the same: **one app service, one persistent volume mounted to `/data`, and one HTTPS domain**.
### 0. Preparation Before Deployment
You need:
- A GitHub account and a Zeabur project;
- A fork of this repository or your own Phosphene repository copy;
- A Zeabur domain prepared for long-term use;
- A password manager to save website passwords, optional Setup Token, and AI Token.
If you just want to deploy the original version, forking this repository is the most convenient. Later, synchronizing upstream updates, viewing your changes, and letting Zeabur listen to submissions will be more clear.
### 1. Create an App Service
1. Create a new project on Zeabur.
2. Choose **Deploy New Service / deploy a new service → Git**.
3. Authorize Zeabur to read GitHub and select the Phosphene repository.
4. The build context remains in the repository root directory and does not need to be changed to `src` or `dist`.
5. Zeabur should recognize the `Dockerfile` in the root directory. No additional startup commands are needed.
6. If the interface requires selecting an HTTP port, fill in `8080`; usually, Zeabur will automatically recognize it from the image.
It is recommended to start with 1 vCPU and 512 MB of memory. Ordinary private instances are usually sufficient; a large number of images will increase volume capacity and backup volume, and sufficient temporary disk space is needed for recovery.
### 2. Mount a Persistent Volume - the Most Important Step
In the newly created **Phosphene App service**, open **Volumes / storage volumes** and add a persistent volume:
| Item | Value to Fill |
| --- | --- |
| Volume Type | Persistent Volume |
| Mount Path / mounting path | `/data` |
| Initial Capacity | at least 1 GB recommended |
This must be the exact `/data`:
- Do not just mount `/data/uploads`, otherwise, images will be retained but the database will be lost;
- Do not mount to `/app/data`, `/root/data`, or `/tmp`;
- Do not add the volume only at the project level without mounting it to the Phosphene service;
- The `VOLUME /data` in Dockerfile is just a mirror declaration and cannot replace the real persistent volume on the platform.
The application will create:
```text
/data/
├── phosphene.sqlite
├── phosphene.sqlite-wal # may exist during operation
├── phosphene.sqlite-shm # may exist during operation
├── uploads/
│ └── proofs/
└── tmp/ # temporary ZIP for recovering uploaded files; cleaned after request ends or restart
```
If the volume is not correctly mounted, the application may still start, but it will be like a brand-new instance again after rebuilding, migrating containers, or service reconstruction. When this happens, check the volume first and do not repeatedly claim ownership.
### 3. Set Environment Variables
Phosphene has no required environment variables on Zeabur. Common variables are:
| Variable | When needed | Suggestion |
| --- | --- | --- |
| `PHOSPHENE_SETUP_TOKEN` | when the domain is publicly available, predictable, or you cannot claim it immediately after deployment | optional; generate at least 24 random characters with a password manager |
| `PHOSPHENE_MCP_AUTH_MODE` | not needed under normal circumstances, no need to fill in manually | keep the default `token` |
| `PUBLIC_URL` | when Zeabur does not inject the public URL correctly | usually do not fill in; fill in the complete `https://...` when needed |
| `LOG_LEVEL` | when troubleshooting requires more or less logs | default `info` |
Time zones do not need to be written as environment variables; common region options will be provided on the first setup and website settings pages.
Do not fill in the following content into Phosphene service environment variables:
- `phosphene_ai_...` AI Token - it should be placed in the AI client or self-built AI backend that calls MCP;
- website login password - it is only submitted through the first setup page and saved as Argon2id hash;
- `Authorization: Bearer ...` - this is the MCP request header, not the Phosphene backend variable.
Do not set `PHOSPHENE_MCP_AUTH_MODE=none` for publicly exposed Zeabur domains. This will allow anyone who can access `/mcp` to read records, create tasks, and adjust points.
### 4. Bind a Domain and Complete Deployment
1. In the service's **Networking / Domains**, generate or bind a domain.
2. Confirm the domain uses HTTPS and points to the Phosphene service.
3. Wait for the build to finish, and the running log shows `Phosphene is ready`.
4. Open `https://your-domain/healthz` and see:
```json
{"status":"ok","version":"1.0.0"}
```
5. Open the domain homepage. If a `PHOSPHENE_SETUP_TOKEN` is set, the first setup page will require it to be entered.
`https://your-domain/mcp` displays 405 when opened directly with a browser, which is normal; MCP works through POST and cannot be judged with GET.
### 5. First Claim
The first setup requires:
1. website login password, at least 10 characters;
2. user's display name;
3. AI partner's display name;
4. time zone used to calculate natural days, streaks, and deadlines.
After successful submission, the page will display a complete `phosphene_ai_...` Token. Save it to the password manager immediately. The database only saves the Token hash, so if it is lost, it cannot be retrieved, and only a new one can be generated in "Settings → AI Connection"; rotating will make all old AI Tokens immediately invalid.
The first setup adopts "the first successful submitter claims". Just opening the webpage will not claim the instance; after successful submission, the entry is permanently closed. Random domains can reduce unintentional access but are not a security boundary and cannot replace the Setup Token and website password.
### 6. Verify Persistent Volume is Effective
After completing the first setup, it is recommended to do a small acceptance test:
1. Modify a name in "Settings → Names and Time" and save it.
2. Perform a normal Restart / restart on the Zeabur service.
3. Reopen the website and confirm that it has not returned to the first setup page and the name still exists.
4. Perform another Redeploy / redeploy and repeat confirmation.
5. View the ready log's `dataDir`; the production container should be `/data`.
If the data still exists after restarting, and it disappears after redeploying, it is usually because the container restarts and reuses the temporary layer, but the new container does not actually mount the persistent volume. Go back to step 2 to check the mount object and path.
### 7. Deploy Using Zeabur Template
The [zeabur-template.yaml](zeabur-template.yaml) in the repository root directory can create a pre-built app, domain, and `/data` volume. The template method saves adding volumes manually but still needs to confirm that the volume is indeed mounted to the Phosphene service's `/data`. The template uses `ghcr.io/3lmglow/phosphene:latest`; to get a new version, you need to redeploy on Zeabur to pull the new image.
More complete update, rollback, snapshot, and permission instructions see [Deployment and Maintenance](docs/DEPLOYMENT.md).
## Connect AI: The Shortest Path
On the website "Settings → AI Connection", copy the MCP Endpoint. The AI Token comes from the last step of the initial setup or the Token rotation result.
| Configuration Item | Value |
| --- | --- |
| URL / Endpoint | `https://your-domain/mcp` |
| Header name | `Authorization` |
| Header value | `Bearer phosphene_ai_your_complete_Token` |
| Transport | Streamable HTTP / HTTP |
These contents are filled in the **AI client or your own AI backend**, not in the Zeabur Phosphene environment variables.
After connecting, you can let AI call `get_overview` first. If it returns the names, time zone, balance, and boundary, it means the URL, transport, and token are correct. Then, create a low-point, no-evidence test task and confirm that the webpage can see it.
The client only allows filling in custom Header keys and values:
```text
Header: X-Phosphene-MCP-Token
Value: phosphene_ai_your_complete_Token
```
Either header can be used; do not put the Token in the URL, do not add it to the frontend code, and do not submit it to GitHub.
## Local Development
Requires Node.js 24 and pnpm 10. Node.js 22 is the minimum running version, but the repository, CI, and image use Node.js 24.
```bash
corepack enable
corepack prepare pnpm@10.13.1 --activate
pnpm install
cp .env.example .env
pnpm dev
```
Open `http://localhost:3000`. The default database is `.data/phosphene.sqlite`, and images are in `.data/uploads`. Open the website and claim this uninitialized instance; after completing the setup, the page only displays the AI Token once.
## Docker Compose
The repository also provides a single-service [docker-compose.yml](docker-compose.yml). It uses the same SQLite + `/data` architecture as Zeabur.
First start:
```bash
git clone https://github.com/3lmglow/Phosphene.git
cd Phosphene
export PHOSPHENE_SETUP_TOKEN="replace-with-a-long-random-value"
docker compose up -d --build
```
Open `http://localhost:8080`. Compose will create a Docker named volume `phosphene-data` and mount it to `/data`. `docker compose down` only stops the container, and the volume remains; `docker compose down -v` will delete the volume along with the container, which will also delete the database and images.
Update:
```bash
git pull --ff-only
docker compose up -d --build
```
Backup the volume before updating. The database migration will be executed automatically when the new container starts.
You can also run the published image directly:
```bash
docker run -d \
--name phosphene \
--restart unless-stopped \
-p 8080:8080 \
-v phosphene-data:/data \
-e PHOSPHENE_SETUP_TOKEN="replace-with-a-long-random-value" \
ghcr.io/3lmglow/phosphene:latest
```
## Update, Hot Update, and Rollback
Phosphene's data and program are separated:
- tasks, points, settings, and images are in `/data`, and the service rebuild continues to use them;
- React webpage, server-side code, and migration are in the container image, and updating them requires rebuilding or redeploying;
- there is no "code hot update" that does not require restarting. The development mode has hot reload, but production updates should go through a formal deployment.
### Zeabur Git Deployment Update
1. Create a `/data` volume snapshot and download the website backup.
2. Merge upstream updates into your GitHub repository.
3. Push to the Zeabur listening branch; enable automatic deployment to build manually point Redeploy.
4. The new container runs migration automatically.
5. Check `/healthz`, website login, historical images, and MCP `get_overview`.
The PWA's Service Worker and Manifest will be re-verified after each deployment. If the installed desktop/mobile PWA still displays the old interface, close it and reopen it; if it still does not update, open the website in a browser and refresh once.
### Rollback
Only change the webpage or server-side, and there is no irreversible database migration. You can roll back to the previous deployment on Zeabur. If the new version has migrated the database, do not assume that the old image can read the new structure; rollback the image first, and then use the upgraded `/data` volume snapshot to restore the entire volume.
Do not use delete service, delete volume or redeploy instance to solve ordinary update issues.
## Choose Connection Method
Regardless of which client is used, Phosphene's formal service entry is the same Streamable HTTP
Endpoint: `https://YOUR_PHOSPHENE_DOMAIN/mcp`. The difference is how the client reaches it and
how to carry the credentials, and it will not create a second database or change the existing website and MCP tools.
| Scenario | Recommended Practice | Server-side Authentication |
| --- | --- | --- |
| Claude Code, MCP clients that support custom headers | directly connect HTTPS `/mcp` | `token` (default) |
| Desktop clients that only accept stdio | use the repository's stdio converter | `token` (default) |
| Self-built AI backend, GPT/GLM invocation layer | backend directly requests `/mcp` | `token` (default) |
| Same machine or trusted intranet, client does not add headers | explicitly switch to no authentication mode | `none` |
| Operit / Termux / Proot | prefer direct connection to Streamable HTTP; only enable authentication on the same machine | `token` or `none` |
### Method 1: Directly Connect through HTTPS (Recommended, Existing Method)
The website "Settings → AI Connection" will display Endpoint and only show once AI Token. Put them in the AI client or AI backend, not in the Phosphene service itself.
First Header:
| Configuration Item | Value |
| --- | --- |
| URL / Endpoint | `https://YOUR_PHOSPHENE_DOMAIN/mcp` |
| Header name / Key | `Authorization` |
| Header value | `Bearer phosphene_ai_your_complete_Token` |
Also supports custom headers:
| Configuration Item | `none` |
| Transport | Streamable HTTP / HTTP |
The first header is recommended:
| Configuration Item | Value |
| --- | --- |
| URL / Endpoint | `https://YOUR_PHOSPHENE_DOMAIN/mcp` |
| Header name / Key | `Authorization` |
| Header value | `Bearer phosphene_ai_your_complete_Token` |
You can also use a custom header:
| Configuration Item | Value |
| --- | --- |
| Header name / Key | `X-Phosphene-MCP-Token` |
| Header value | `phosphene_ai_your_complete_Token` |
The permissions are the same; choose one. If you send both, the two values must represent the same token; otherwise, the request will be rejected. Token does not support being placed in URL query parameters.
General configuration example:
```json
{
"mcpServers": {
"phosphene": {
"type": "http",
"url": "https://YOUR_PHOSPHENE_DOMAIN/mcp",
"headers": {
"Authorization": "Bearer YOUR_AI_TOKEN"
}
}
}
}
```
Claude Code can directly add a remote HTTP MCP:
```bash
claude mcp add --transport http phosphene https://YOUR_PHOSPHENE_DOMAIN/mcp \
--header "Authorization: Bearer YOUR_AI_TOKEN"
```
## Local Development
Requires Node.js 24 and pnpm 10. Node.js 22 is the minimum running version, but the repository, CI, and image uniformly use Node.js 24.
```bash
corepack enable
corepack prepare pnpm@10.13.1 --activate
pnpm install
cp .env.example .env
pnpm dev
```
Open `http://localhost:3000`. The default database is `.data/phosphene.sqlite`, and images are in `.data/uploads`. Open the website and claim this uninitialized instance; after completing the setup, the page only displays the AI Token once.
## Docker Compose
The repository also provides a single-service [docker-compose.yml](docker-compose.yml). It uses the same SQLite + `/data` architecture as Zeabur.
First start:
```bash
git clone https://github.com/3lmglow/Phosphene.git
cd Phosphene
export PHOSPHENE_SETUP_TOKEN="replace-with-a-long-random-value"
docker compose up -d --build
```
Open `http://localhost:8080`. Compose creates a Docker named volume `phosphene-data` and mounts it to `/data`. `docker compose down` only stops the container, and the volume remains; `docker compose down -v` will delete the volume along with the container, which will also delete the database and images.
Update:
```bash
git pull --ff-only
docker compose up -d --build
```
Update before backup volume. Database migration will be executed automatically when the new container starts.
You can also run the published image directly:
```bash
docker run -d \
--name phosphene \
--restart unless-stopped \
-p 8080:8080 \
-v phosphene-data:/data \
-e PHOSPHENE_SETUP_TOKEN="replace-with-a-long-random-value" \
ghcr.io/3lmglow/phosphene:latest
```
## Update, Hot Update, and Rollback
Phosphene's data and program are separated:
- tasks, points, settings, and images are in `/data`, and the service rebuild continues to use them;
- React webpage, server-side code, and migration are in the container image, and updating them requires rebuilding or redeploying;
- there is no "code hot update" that does not require restarting. The development mode has hot reload, but production updates should go through a formal deployment.
### Zeabur Git Deployment Update
1. Create a `/data` volume snapshot and download the website backup.
2. Merge upstream updates into your GitHub repository.
3. Push to the Zeabur listening branch; enable automatic deployment to build manually point Redeploy.
4. The new container runs migration automatically.
5. Check `/healthz`, website login, historical images, and MCP `get_overview`.
The PWA's Service Worker and Manifest will be re-verified after each deployment. If the installed desktop/mobile PWA still displays the old interface, close it and reopen it; if it still does not update, open the website in a browser and refresh once.
### Rollback
Only change the webpage or server-side, and there is no irreversible database migration. You can roll back to the previous deployment on Zeabur. If the new version has migrated the database, do not assume that the old image can read the new structure; rollback the image first, and then use the upgraded `/data` volume snapshot to restore the entire volume.
Do not use delete service, delete volume or redeploy instance to solve ordinary update problems.
## Choose Connection Method
Regardless of which client is used, Phosphene's formal service entry is the same Streamable HTTP
Endpoint: `https://YOUR_PHOSPHENE_DOMAIN/mcp`. The difference is how the client reaches it and
how to carry the credentials, and it will not create a second set of databases or change the existing website and MCP tools.
| Scenario | Recommended Practice | Server-side Authentication |
| --- | --- | --- |
| Claude Code, MCP clients that support custom headers | directly connect HTTPS `/mcp` | `token` (default) |
| Only accept stdio | use the repository's stdio converter | `token` (default) |
| Self-built AI backend, GPT/GLM invocation layer | backend directly requests `/mcp` | `token` (default) |
| Same machine or trusted intranet, client does not add headers at all | explicitly switch to no authentication mode | `none` |
| Operit / Termux / Proot | prefer direct connection to Streamable HTTP; only enable authentication on the same machine when necessary | `token` or `none` |
### Method 1: Directly Connect through HTTPS (Recommended, Existing Method Unchanged)
The website "Settings → AI Connection" will display Endpoint and only show once AI Token. Put them in the AI client or AI backend, not in Phosphene service itself.
The recommended header:
| Configuration Item | Value |
| --- | --- |
| URL / Endpoint | `https://YOUR_PHOSPHENE_DOMAIN/mcp` |
| Header name / Key | `Authorization` |
| Header value | `Bearer phosphene_ai_your_complete_Token` |
Also support custom header:
| Configuration Item | Value |
| --- | --- |
| Header name / Key | `X-Phosphene-MCP-Token` |
| Header value | `phosphene_ai_your_complete_Token` |
The permissions are the same; choose one. If you send both, the two values must represent the same token; otherwise, the request will be rejected. Token does not support being placed in URL query parameters.
General configuration example:
```json
{
"mcpServers": {
"phosphene": {
"type": "http",
"url": "https://YOUR_PHOSPHENE_DOMAIN/mcp",
"headers": {
"Authorization": "Bearer YOUR_AI_TOKEN"
}
}
}
}
```
Claude Code can directly add remote HTTP MCP:
```bash
claude mcp add --transport http phosphene https://YOUR_PHOSPHENE_DOMAIN/mcp \
--header "Authorization: Bearer YOUR_AI_TOKEN"
```
### Method 2: Using a Local Bridge for stdio Clients
Some desktop clients can only launch local commands and cannot directly configure remote HTTP connections. Phosphene provides `dist/server/stdio-bridge.js` to act as a bridge. The client communicates with it using stdio, and it uses your URL and Token to access the original Phosphene service. It does not store business data and does not bypass server-side authentication.
First, clone and build it locally:
```bash
pnpm install --frozen-lockfile
pnpm build
```
Then, in the client's MCP configuration, fill in:
```json
{
"mcpServers": {
"phosphene": {
"command": "node",
"args": ["/absolute/path/to/Phosphene/dist/server/stdio-bridge.js"],
"env": {
"PHOSPHENE_MCP_URL": "https://YOUR_PHOSPHENE_DOMAIN/mcp",
"PHOSPHENE_MCP_TOKEN": "phosphene_ai_your_full_Token"
}
}
}
}
```
In Windows paths, backslashes should be written as `\\`. If `PHOSPHENE_MCP_URL` only includes the domain, the bridge will automatically append `/mcp`. The Token can be the original value or already prefixed with `Bearer `. These two variables are for the local bridge and should not be set in the Zeabur Phosphene service.
### Method 3: Connecting to a Self-built AI Backend or Custom Client
Self-built server-side invocation layers can use:
```env
PHOSPHENE_MCP_URL=https://YOUR_PHOSPHENE_DOMAIN/mcp
PHOSPHENE_MCP_TOKEN=phosphene_ai_your_full_Token
```
When requesting, compose `Authorization: Bearer ${PHOSPHENE_MCP_TOKEN}` or send `X-Phosphene-MCP-Token: ${PHOSPHENE_MCP_TOKEN}`.
If the client is on the same machine or in a truly isolated trusted intranet and cannot send headers, you can set on the Phosphene server:
```env
PHOSPHENE_MCP_AUTH_MODE=none
```
After restarting the service, `/mcp` will no longer check the Token. To restore the original Token authentication, set it back to `token` and restart. **Do not use `none` on a publicly exposed Zeabur domain**: anyone who can access the address can create tasks, adjust points, and read private records. Browser frontends should not directly hold AI Tokens; custom web pages should forward through their own backend.
### Method 4: Operit, Termux, and Proot
If Phosphene is running on the same Android device, the client address should be filled with `http://127.0.0.1:actual_port/mcp`, not relying on `localhost` which might resolve to IPv6. Confirm step by step:
1. The client's transport is `streamable-http` or `http`, not the old SSE.
2. The URL ends with `/mcp`, and the port matches the Phosphene startup log.
3. If the client can configure headers, keep the default `token`; only use `PHOSPHENE_MCP_AUTH_MODE=none` if it's on the same machine and the client does not support headers.
If Operit connects to a Zeabur instance, continue using the HTTPS domain and Token, and do not disable public network authentication. Clients that only support old SSE handshakes cannot directly connect to the current stateless endpoint and need to upgrade.
### Claude.ai Web and Mobile
This release does not include OAuth 2.1. Claude's remote custom connector typically requires a complete OAuth flow for protected services, not just a static header. A reliable implementation must include an authorization page, PKCE, client registration, access token, refresh token, revocation, and persistence. Implementing only part of it might result in connections that seem to add but actually cannot renew or have permission issues. Therefore, Phosphene currently does not claim to support direct authorization from Claude.ai.
Claude can also connect to an unauthenticated remote MCP, but turning a public instance into `none` for the web to work would expose the entire private data, which is not recommended. OAuth support will be designed separately as a complete security feature when delivered, not affecting current static Token clients. Relevant technical requirements can refer to [Anthropic's remote connector documentation](https://support.anthropic.com/en/articles/11503834-building-custom-integrations-via-remote-mcp-servers).
All Tokens should only be saved in trusted backend environment variables or local private configurations, not in browser variables, public repositories, logs, or screenshots. For more complete handshake and troubleshooting descriptions, see [docs/MCP.md](docs/MCP.md).
## Seven MCP Tools
| Tool | Purpose |
| --- | --- |
| `create_task` | Create one-time or daily recurring tasks |
| `query_tasks` | Query tasks, submit tasks, and image review content |
| `manage_task` | Edit, cancel, judge failure, audit, pause/resume series |
| `get_overview` | Query points, combo, statistics, today's status, and pending queue |
| `query_history` | Query tasks, points, redemption, and audit history |
| `manage_rewards` | Manage rewards and fulfill user's redemption |
| `adjust_points` | Reward, deduct points, or correct within user boundaries and daily limits |
All write tools require `idempotency_key`. When a client retries the same request, it must reuse the same key.
`manage_rewards` includes listing, creating, modifying, archiving, restoring, and querying redemption operations. AI can directly create custom redemption projects that belong to this instance. When a user clicks to redeem, points will be immediately deducted in the same transaction, and the record will enter "waiting for fulfillment". Only when AI actually fulfills and calls the fulfillment operation will the status change to "fulfilled".
Archiving removes a project from the user's redemption mall and does not destroy existing redemption history or continue to occupy the page. To re-list, use `restore`. AI can only create new tasks that require no evidence, pure text, or "text + image" evidence; it will not create new tasks that might only have images and cannot be reliably audited. Existing pure image tasks still run according to the original rules.
When AI judges a task failed and requires confirmation, it must fill in a specific reason. When a user opens the task again, they will see this description and can modify and resubmit based on the previous text. Pausing a daily recurring task will immediately cancel instances that have not been submitted that day, making them leave the today's to-do list. Already submitted, completed, or entered historical records will not be revoked. If restored before the daily deadline, instances canceled due to pause will also be restored.
## Points and Combo
- Task points: `base_points × easy 1 / medium 2 / hard 3`
- Failure or overdue: deduct 50% of the task's final points, but the balance does not go below 0
- "Penalty intensity" 0–5 is a preference signal provided to AI to understand boundaries and does not change the server-side fixed 50% task deduction formula
- Each natural day, completing at least one task of any type continues the combo
- Combo day 1 +0; days 2–5 +1 each; days 6–7 +2 each; day 8 and beyond +3 each
- When AI delays auditing, the completion record is based on the user's actual submission date, and subsequent combos are calculated through correction flow
- The website selects the timezone from nine common regions; the server is responsible for settlement, and AI only reads the overview timezone in tasks with dates
## Installing on Mobile or Desktop
Phosphene is a complete PWA. Android, Chrome, and Edge can be installed from the browser's installation prompt or "Settings → Data and backup". iPhone/iPad use Safari's share menu and select "Add to Home Screen". After installation, open it in an independent window, adapting to the notch and bottom safety area.
Offline capabilities only cache the application shell and static resources, not `/api`, MCP, private task data, or evidence images. When offline, the application shell can be opened, but viewing or submitting private data still requires a connection to your Phosphene service.
## Image Privacy
- Only accept genuine JPEG, PNG, WebP
- Up to 4 images at a time, maximum 10 MB each, up to 24 million pixels
- Server-side rotation to the correct direction and re-encoding to WebP, without retaining original EXIF/GPS
- Website image routing requires user session; AI only receives review previews through authenticated MCP
- In single-service mode, images are saved in `/data/uploads` and are not publicly accessible from static directories
## Backup and Restore
Phosphene has two levels of backup:
| Method | Includes | Suitable for |
| --- | --- | --- |
| `/data` persistent volume snapshot | SQLite, WAL/SHM state, and all images | Pre-upgrade protection, whole instance disaster recovery |
| Website ZIP | Business tables, idempotency records, image originals, and review previews; does not cover login credentials and AI Token | Application-level export, migration, and business point-in-time recovery |
Create a `/data` volume snapshot at least before each upgrade. When deleting a Zeabur service, carefully confirm whether to delete the volume simultaneously; deleting the volume is irreversible. Do not copy only the `phosphene.sqlite` single file while the application is running, as there might be unmerged data in WAL.
The website ZIP uses database consistency snapshots, streaming download, and disk temporary storage recovery. Backups with images can be restored in-place on the original instance. During recovery, the system will briefly enter maintenance status, new business requests return 503, and health checks remain available. Images are first written to new private object keys; only after all checksums and database transactions are successful, old files are cleaned.
The website recovery entrance requires the current login password, designed not to overwrite passwords, sessions, or AI Tokens. During recovery, ZIP, old images, and new images coexist in `/data` for a short time; create a volume snapshot before starting and confirm sufficient space. Only restore backups you trust and are explicitly sourced. Complete process, capacity estimation, format compatibility, and failure handling see [Backup and Restore](docs/BACKUP.md).
## Environment Variables
| Variable | Description |
| --- | --- |
| `PORT` | HTTP listening port; provided automatically by Zeabur |
| `PUBLIC_URL` | Optional public HTTPS address; if not filled, automatically use `ZEABUR_WEB_URL` |
| `PHOSPHENE_SETUP_TOKEN` | Optional initial setup protection; leave blank for the first visitor to claim, and the website will require the exact same value after setting |
| `PHOSPHENE_MCP_AUTH_MODE` | MCP authentication mode; default `token`, `none` only for same-machine or trusted private network |
| `PHOSPHENE_DATA_DIR` | Persistence root directory; production default `/data` |
| `SQLITE_PATH` | Optional SQLite file path override, must be within the data directory in production |
| `LOCAL_STORAGE_PATH` | Optional image path override, must be within the data directory |
See [.env.example](.env.example) for a complete example.
## Document Index
- [Product Specifications](docs/PRODUCT_SPEC.md): roles, tasks, points, combo, rewards, and release thresholds
- [Deployment and Operations](docs/DEPLOYMENT.md): Zeabur, Docker, volumes, upgrades, rollbacks, and backup strategies
- [Backup and Restore](docs/BACKUP.md): ZIP content, streaming recovery, capacity estimation, checksums, and exercise steps
- [MCP Connection and Tool Contract](docs/MCP.md): connection methods, system prompts, parameters, and handshake troubleshooting
- [Architecture Description](docs/ARCHITECTURE.md): services, database, task materialization, and consistency design
- [Troubleshooting](docs/TROUBLESHOOTING.md): crash loop, data loss, 401, 405, PWA, and image issues
- [Known Issues](docs/KNOWN_ISSUES.md): important issues confirmed by this warehouse review, not yet fixed
- [Security Instructions](SECURITY.md): deployment checks and vulnerability reporting methods
## Quality Gate
```bash
pnpm typecheck
pnpm test
pnpm build
pnpm check
```
CI performs type checking, automated testing, deployment manifest verification, production build, and `git diff --check`.
## Security Boundary
- AI cannot modify passwords, user boundaries, or redeem for users
- User boundary modifications increase the version number and are written to the audit log
- AI's active judgment of task failure and `adjust_points(kind="penalty")` comply with `punishments_paused` and share the daily AI deduction limit; the system automatically overdue still settles according to task rules
- MCP Token is displayed once, and the database only saves the SHA-256 hash, which can be rotated at any time
- Login password uses Argon2id; write requests need SameSite Cookie and CSRF Token
- The instance is claimed by the first person to successfully submit the setting; the claim write is atomic and cannot be initialized again after success
- An additional layer of deployer's credential can be added for the first claim through `PHOSPHENE_SETUP_TOKEN`
- Website sessions use unpredictable random Cookies; the server only saves their SHA-256 and does not need an additional static Session Secret
- Single-service images limit Node heap; SQLite has no WebAssembly initialization peak, suitable for small private instances
- Production startup rejects temporary databases or out-of-bounds persistence paths
Read [SECURITY.md](SECURITY.md) before deployment.
## License
[MIT](LICENSE)
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
awesome-mcp-servers
A collection of MCP servers.
git
A Model Context Protocol server for Git automation and interaction.
oh-my-opencode
Background agents · Curated agents like oracle, librarians, frontend...
TrendRadar
TrendRadar: Your hotspot assistant for real news in just 30 seconds.
Appwrite
Build like a team of hundreds