Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Verify web application
on:
push:
branches: [main, 'codex/**']
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run build && git diff --exit-code -- index.html
- run: npm test
- run: npx playwright install --with-deps chromium
- run: npm run test:motion
- run: npm run test:browser
- uses: actions/upload-artifact@v4
if: always()
with:
name: browser-validation
path: .test-results/
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DS_Store
node_modules/
dist/
.test-results/
macos/
31 changes: 14 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ✨ ConversationsWithGod

<p align="center">
<img src="img/logo.png" alt="ConversationsWithGod Logo" width="280">
<img src="img/logo.png" alt="ConversationsWithGod Logo" width="160">
</p>

<p align="center">
Expand Down Expand Up @@ -40,26 +40,28 @@ We all need space to process our thoughts, ask deep questions, and listen to our
- **🔒 Complete Privacy**: All conversations stay on your device
- **👁️ Ephemeral Memory**: Messages naturally fade and blur over time, mimicking real memory
- **🎨 Beautiful Interface**: Clean, paper-like design with light and dark modes
- **💾 Export Options**: Save your conversations in multiple formats
- **💾 Export Options**: Complete backups, readable text, current API request bodies and fine-tuning datasets
- **🌿 Long Conversations**: Continuous history scrolling with only visible messages rendered
- **↩️ Undo**: Undo message deletion or clearing a conversation
- **🤖 LLM Training Ready**: Export in formats compatible with various AI models
- **📱 Fully Responsive**: Works on desktop and mobile devices

## 🔒 Privacy

Your conversations are stored only on your device using browser localStorage. Nothing is ever sent to a server. There are no analytics, no tracking, and no cookies. Your thoughts remain entirely your own.
Conversations are stored in browser IndexedDB, migrating older localStorage records. Nothing is ever sent to a server. There are no analytics, no tracking, and no cookies. Your thoughts remain entirely your own.

### Natural Privacy Protection

<p align="center">
<img src="img/privacy-blur.png" alt="Privacy Through Fading" width="480">
</p>

Rather than relying on passwords or encryption, ConversationsWithGod implements privacy the way human memory works:
The fading display evokes the way human memory changes. It is a visual effect, not encryption or deletion:

- **Time-Based Fading**: Older messages gradually become blurry and fade away
- **Five Stages of Aging**: Messages progress through increasing levels of obscurity
- **Natural Security**: Anyone glancing at your screen sees only your recent thoughts clearly
- **No Permanent Record**: The fading visual effect creates a sense of impermanence
- **Visual Fading**: The original text and timestamps remain saved and exportable. Both fade together on screen.

This design reflects how memories and conversations naturally fade with time, providing both privacy and encouraging a focus on the present moment.

Expand All @@ -73,19 +75,14 @@ This design reflects how memories and conversations naturally fade with time, pr

## 🧠 Exporting for AI Training

Your self-conversations can be valuable training data for personalizing AI models. ConversationsWithGod supports exporting in formats compatible with most major LLM platforms:
Choose a full backup for safekeeping, a request body to continue a dialogue with a model, or a JSONL dataset for fine-tuning.

- **🟢 OpenAI/ChatGPT** (JSON, JSONL)
- **🟣 Anthropic/Claude** (Human/Assistant format)
- **🔵 Meta/LLaMA** (Instruction format)
- **🟠 ShareGPT** (Community format)
- **🟡 Alpaca** (Instruction tuning format)
- **⚪ Plain Text** (Universal format)
- OpenAI-compatible Chat Completions, OpenAI Responses, Anthropic Messages and Gemini generateContent
- OpenAI supervised fine-tuning JSONL with answer weights, Hugging Face / TRL messages JSONL and ShareGPT JSONL
- Complete JSON backup, portable messages history, plain text
- Legacy Claude text, Llama 2 INST, ShareGPT JSON and Alpaca JSON

<p align="center">
<img src="img/export-formats1.png" alt="Export Format Options" width="480">
<img src="img/export-formats2.png" alt="Export Format Options" width="480">
</p>
Saving starts with readable text. Choose another use to reveal backup, AI continuation or fine-tuning options. All exports are generated locally; the app does not call model APIs. Supply your provider's model ID when preparing an API request. See [the export guide](docs/EXPORTS.md) for continuation, training context, loss masking and current API schemas.

## 🕊️ The Philosophy Behind It

Expand Down Expand Up @@ -116,7 +113,7 @@ Every star, fork, and share helps this little light reach more seekers in a digi

## 👥 Contributing

Contributions are welcome! Feel free to open issues or submit pull requests on the [GitHub repository](https://github.com/studentiz/ConversationsWithGod).
Contributions are welcome! Feel free to open issues or submit pull requests on the [GitHub repository](https://github.com/studentiz/ConversationsWithGod). See [development instructions](docs/DEVELOPMENT.md) and [validation results](docs/VALIDATION.md) for building and checking the web version.

---

Expand Down
28 changes: 28 additions & 0 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Develop and build

Node.js 24 is used for the web build and tests.

```sh
npm ci
npm run build
npm test
npx playwright install chromium
npm run test:motion
npm run test:browser
```

`web/index.template.html` contains the original paper UI and interaction code. `web/storage.js`, `web/transcript.js` and `web/exports.js` are inlined by the build into the standalone root `index.html`. GitHub Pages serves that generated file from `main` as before.

The public build is a single standalone HTML file plus optional PWA assets. `npm run build:icons` regenerates the web icons and README logo from `icons/mark.svg`, using the same borderless dialogue-bubble shapes and paper/gray/green palette as the interface.

## Storage

Pages migrates the previous `chat_messages` localStorage array into IndexedDB atomically and only removes the source after a successful transaction. Subsequent appends write one message. Standalone browsers that deny IndexedDB retain the localStorage fallback. A storage failure keeps the current text in memory, gives an actionable error and lets the next save recover the full state. Damaged history is not overwritten.

## Rendering and motion

The transcript uses variable-height virtual rows with overscan, measured height caching, binary-search lookup and explicit scroll anchoring. Native browser anchoring is disabled to avoid double adjustment when spacers change. Every message remains in the history and is reachable by continuous scrolling; exporting reads the full history, not the rendered DOM.

Only a newly sent short message gets a character-opacity reveal. Grapheme segmentation preserves composed emoji and text, spans are capped at 160. A single character fades in over 600 ms; phrases have at least a 700 ms span between the first and last character starts, with a 420 ms fade for each. Longer passages use approximately 65 ms between starts, capped at a six-second stagger, and collapse back to one text node within 6.52 seconds. Long messages render immediately. Menus and dialogs use short opacity / transform transitions. The reduced-motion preference removes reveals and transitions; hidden documents stop maintenance timers and finish active text reveals. Idle conversations have no continuous decorative animation. Aging is applied to a shared content wrapper so the body and timestamp fade and blur together, while deletion controls stay clear. There is no added fading toggle or backup import item.

These choices follow [Apple's motion guidance](https://developer.apple.com/design/human-interface-guidelines/motion): purposeful, brief feedback, input available during animation, and accessibility preferences. Smoothness and power are tested separately from correctness; there is no measured battery-life claim.
44 changes: 44 additions & 0 deletions docs/EXPORTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Export a dialogue for another model

The two voices are written by you. In exports, the seeker becomes `user` and the voice of inner wisdom becomes `assistant`. Choose **Save a copy… → Backup** to preserve the exact individual messages, timestamps, names and order. Fading affects the display only.

Opening **Save a copy…** starts with readable text. You can save immediately, or change **Save for** to a backup, AI continuation, fine-tuning, or another format. Only the fields for that use appear. Additional model instructions and training context are under **Options**; model instructions are off by default. These operations generate files locally and never call a model or upload a conversation.

## Continue a conversation

| Export | Request body | Where it fits |
| --- | --- | --- |
| Messages history | `messages` with `role` and `content` | SDKs and local models; choose your own chat template |
| OpenAI-compatible Chat Completions | `model`, `messages` | Compatible OpenAI, DeepSeek, Qwen and local endpoints |
| OpenAI Responses | `model`, `input`, optional `instructions` | Responses API |
| Anthropic Messages | `model`, `max_tokens`, `messages`, optional top-level `system` | Messages API |
| Gemini generateContent | `contents` with `parts`, optional `systemInstruction` | Model chosen in the request URL |

Enter the model ID your provider supplies. If the dialogue already ends with an answer, enter your next question in the export dialog. That question is added to the exported request only. Supply endpoint, authentication and provider-specific settings in your own caller. The Anthropic starter output limit is 2048 tokens; adjust it in your caller.

For example, in Python, an exported compatible request body can be used with a configured client:

```python
import json
from openai import OpenAI

client = OpenAI() # reads credentials from your environment
with open("request.json", encoding="utf-8") as file:
request = json.load(file)
response = client.chat.completions.create(**request)
print(response.choices[0].message.content)
```

Adjacent messages from the same role, which can occur after deleting a turn, are joined with a blank line. Their text remains intact. Exports that require a user-first dialogue report an assistant-first history instead of silently removing it; use the complete backup or messages history to retain that history as-is.

## Fine-tune

Choose **Fine-tuning a model**, then your training tool. The file is a JSONL dataset. Each line ends at an answered assistant turn. The context setting limits previous **exchanges**, not tokens; use the chosen model's tokenizer to check the final examples. Incomplete final questions are retained in backups and continuation history, and excluded from training examples. An assistant-only opening is excluded with a visible explanation.

- **OpenAI supervised fine-tuning:** messages JSONL. The newest assistant answer has `weight: 1`; earlier answers in the same window have `weight: 0`, preventing those context answers from becoming repeated loss targets. OpenAI currently requires at least 10 examples; the dialog reports smaller datasets. Review your examples before combining conversations and uploading.
- **Hugging Face / TRL:** messages JSONL without provider-specific weights. Select assistant loss masking in your trainer. With zero previous exchanges, each answered pair occurs once; with overlapping context, your trainer determines which earlier answers contribute to loss.
- **ShareGPT:** `conversations` JSONL with `from` / `value`, for training tools accepting this schema. Configure the tool's dataset mapping and chat template.

Human/Assistant text, Llama 2 INST, whole-conversation ShareGPT JSON and Alpaca JSON remain available under **Other formats**. Use the current model's own template for newer Llama and Qwen models. Alpaca exports answered pairs without prior dialogue context; it is not a complete backup.

Sources checked on 2026-10-11: [OpenAI SFT](https://developers.openai.com/api/docs/guides/supervised-fine-tuning), [OpenAI loss weights](https://developers.openai.com/api/docs/guides/fine-tuning-best-practices), [Responses input](https://developers.openai.com/api/reference/resources/responses/methods/create), [Anthropic Messages](https://platform.claude.com/docs/en/api/messages/create), [Gemini generateContent](https://ai.google.dev/api/generate-content), [TRL datasets and loss configuration](https://huggingface.co/docs/trl/sft_trainer). Automated tests validate emitted data and edge cases; they do not perform paid API calls or actual model training.
19 changes: 19 additions & 0 deletions docs/VALIDATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Validation · 2026-10-11

Local hardware: Apple M4 Pro, macOS 15.8. Chrome runs headlessly at 390 × 844 for the history benchmark. Both versions use the same message contents, timestamps, viewport, browser and first-frame measurement. Baseline HTML is pinned to GitHub commit `6a4ae6e9a7980d7d83af4e41ee6b75671f341ee2`.

| History | Before: open | After: open | Before: live message nodes | After: live message nodes | Before: send median | After: send median |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| 3,000 messages | 778 ms | 178 ms | 3,003 | 13 | 22.3 ms | 18.4 ms |
| 10,000 messages | 2,310 ms | 316 ms | 10,003 | 14 | 79.2 ms | 6.2 ms |

Opening measurements include the new version's initial migration. Send timing measures click-to-next-animation-frame; it is not disk durability latency. The data is one local run with three sends per condition, rather than a cross-device performance guarantee. In the 90-frame scripted scroll probe, both versions recorded zero intervals above 34 ms; after-change p95 intervals were 16.7 ms in both sizes. This probe alone does not establish smoothness of every animation. Run `npm run benchmark` to reproduce; raw results go into `.test-results/performance.json`.

Browser integration covers 100, 3,000 and 10,000 messages: complete migration and reload, continuous top/middle/end history access, bounded row count, stable-ID deletion and undo, full-history download, composition input, multiline input, bounded character animation and cleanup, reduced motion, quota failure recovery, corrupt-history preservation, offline reopening, standalone HTML, font changes and fading. Notification rectangles remain below the header and above the composer in portrait and small landscape layouts. The normal conversation has no persistent save/status footer, connection messages, font-change messages or automatic installation banner. Saving starts with a readable copy; backup and model settings appear only when selected. A storage failure offers a working Save a copy action, opening a damaged history can be retried. Browser tests exercise these controls and verify continuation and training exports while offline, without network requests after initial page loading.

Export-format tests cover backup fidelity, provider-specific request fields, training target weights, incomplete turns, adjacent-role merging, Unicode text and the retained legacy formats.

API requests and fine-tuning files are validated against the linked schemas and local tests. No paid model calls or training jobs were performed. Battery consumption has not been measured; the implementation bounds rendering and character spans, stops maintenance when hidden and avoids continuous idle animation.


The timestamp regression first failed with a clear timestamp beside blurred text; after the fix the inherited blur is identical for both, with the delete control unaffected. A three-character Chinese phrase previously reached 0.96 opacity on the last character after 210 ms; it now still has its last character at zero opacity then, completes within the bounded reveal time and retains its exact text. These focused regressions run with `npm run test:motion`. Browser integration also checks compact 320 × 400 / 320 × 568, landscape, tablet and desktop dimensions, complete reveal cleanup, reduced motion, and the removal of the two unrequested menu items.
54 changes: 54 additions & 0 deletions docs/performance.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
[
{
"version": "old",
"messages": 3000,
"bootMs": 778,
"domMessages": 3003,
"sendMs": [
23.399999998509884,
22.30000000447035,
22.100000001490116
],
"scrollFrameP95Ms": 16.700000000000273,
"scrollFramesOver34Ms": 0
},
{
"version": "old",
"messages": 10000,
"bootMs": 2310,
"domMessages": 10003,
"sendMs": [
86.5,
79.10000000149012,
79.19999999552965
],
"scrollFrameP95Ms": 16.700000000000728,
"scrollFramesOver34Ms": 0
},
{
"version": "new",
"messages": 3000,
"bootMs": 178,
"domMessages": 13,
"sendMs": [
18.599999994039536,
14.600000001490116,
18.399999998509884
],
"scrollFrameP95Ms": 16.700000000000045,
"scrollFramesOver34Ms": 0
},
{
"version": "new",
"messages": 10000,
"bootMs": 316,
"domMessages": 14,
"sendMs": [
18.200000002980232,
4.5,
6.200000002980232
],
"scrollFrameP95Ms": 16.700000000000273,
"scrollFramesOver34Ms": 0
}
]
Binary file modified icons/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icons/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icons/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icons/icon-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icons/icon-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions icons/mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icons/maskable-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified img/export-formats1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified img/export-formats2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified img/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified img/privacy-blur.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified img/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading