mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
Merge pull request #36 from M3gA-Mind/feat/memory-flow
Feat/memory flow
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
{ "mcpServers": { "alphaHuman": { "type": "http", "url": "https://alphahuman.readme.io/mcp" } } }
|
||||
{ "mcpServers": { "alphahuman": { "type": "http", "url": "https://openhuman.readme.io/mcp" } } }
|
||||
|
||||
@@ -58,7 +58,7 @@ This project is a **crypto-focused communication platform** built with Tauri v2,
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
frontend-runner-alphahuman/
|
||||
frontend-runner-openhuman/
|
||||
├── .claude/ # Claude AI configuration
|
||||
│ ├── rules/ # Modular documentation
|
||||
│ └── agents/ # Subagent configurations
|
||||
@@ -86,7 +86,7 @@ frontend-runner-alphahuman/
|
||||
|
||||
## Key Configuration Files
|
||||
|
||||
- `tauri.conf.json` - Tauri configuration (app identifier: com.alphahuman.app)
|
||||
- `tauri.conf.json` - Tauri configuration (app identifier: com.openhuman.app)
|
||||
- `Cargo.toml` - Rust dependencies and workspace configuration
|
||||
- `package.json` - Node.js dependencies and scripts
|
||||
- `vite.config.ts` - Vite build configuration with Node.js polyfills
|
||||
|
||||
@@ -116,7 +116,7 @@ adb kill-server # Stop ADB server
|
||||
adb start-server # Restart ADB server
|
||||
|
||||
# Force stop app on device:
|
||||
adb shell am force-stop com.alphahuman.app
|
||||
adb shell am force-stop com.openhuman.app
|
||||
|
||||
# Kill Gradle daemon if stuck:
|
||||
# macOS/Linux:
|
||||
|
||||
@@ -24,7 +24,7 @@ Web Browser Backend Server Desktop App (Tauri
|
||||
│<─────────────────────────────│ │
|
||||
│ │ │
|
||||
│ 5. Redirect to │ │
|
||||
│ alphahuman://auth?token= │ │
|
||||
│ openhuman://auth?token= │ │
|
||||
│─────────────────────────────────────────────────────────────>│
|
||||
│ │ │
|
||||
│ │ 6. Rust invoke │
|
||||
@@ -58,7 +58,7 @@ Initiates Telegram OAuth. The frontend opens this URL in the system browser.
|
||||
2. On callback, validate Telegram user data
|
||||
3. Create or find user in database
|
||||
4. Generate a short-lived `loginToken` (single-use, 5-minute TTL)
|
||||
5. Redirect to `alphahuman://auth?token=<loginToken>`
|
||||
5. Redirect to `openhuman://auth?token=<loginToken>`
|
||||
|
||||
### 2. `POST /api/auth/web-complete`
|
||||
|
||||
@@ -181,7 +181,7 @@ Called by the Tauri Rust command `exchange_token` (NOT browser fetch). Exchanges
|
||||
3. **HTTPS only** in production — tokens travel as URL parameters and POST bodies
|
||||
4. **Rate limiting** — on `/api/auth/web-complete` and `/auth/desktop-exchange`
|
||||
5. **Token entropy** — minimum 256 bits of randomness
|
||||
6. **Deep link validation** — the desktop app only processes `alphahuman://auth` paths; ignore unknown paths
|
||||
6. **Deep link validation** — the desktop app only processes `openhuman://auth` paths; ignore unknown paths
|
||||
7. **Telegram data verification** — validate the `hash` field using your bot token per Telegram docs
|
||||
|
||||
## Implementation Details
|
||||
@@ -226,14 +226,14 @@ Set `VITE_BACKEND_URL` environment variable for different environments.
|
||||
|
||||
## Frontend Integration Points
|
||||
|
||||
| File | Role |
|
||||
| -------------------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| `src/main.tsx` | Lazy-imports and starts the deep link listener |
|
||||
| `src/utils/desktopDeepLinkListener.ts` | Parses deep link -> invokes Rust `exchange_token` -> stores session -> navigates |
|
||||
| `src/utils/deeplink.ts` | Web-side: calls `/api/auth/web-complete` and builds `alphahuman://auth?token=...` URL |
|
||||
| `src/utils/config.ts` | Backend URL configuration |
|
||||
| `src/pages/Login.tsx` | Opens `GET /auth/telegram?platform=desktop` in browser |
|
||||
| `src-tauri/src/lib.rs` | Rust `exchange_token` command using `reqwest` (CORS-free) |
|
||||
| File | Role |
|
||||
| -------------------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| `src/main.tsx` | Lazy-imports and starts the deep link listener |
|
||||
| `src/utils/desktopDeepLinkListener.ts` | Parses deep link -> invokes Rust `exchange_token` -> stores session -> navigates |
|
||||
| `src/utils/deeplink.ts` | Web-side: calls `/api/auth/web-complete` and builds `openhuman://auth?token=...` URL |
|
||||
| `src/utils/config.ts` | Backend URL configuration |
|
||||
| `src/pages/Login.tsx` | Opens `GET /auth/telegram?platform=desktop` in browser |
|
||||
| `src-tauri/src/lib.rs` | Rust `exchange_token` command using `reqwest` (CORS-free) |
|
||||
|
||||
## Phone OTP Flow (Future)
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The `alphahuman://` custom URL scheme is used to hand off authentication from a web browser to the Tauri desktop app. This document covers platform-specific behavior, gotchas, and build requirements discovered during development.
|
||||
The `openhuman://` custom URL scheme is used to hand off authentication from a web browser to the Tauri desktop app. This document covers platform-specific behavior, gotchas, and build requirements discovered during development.
|
||||
|
||||
## Scheme Registration
|
||||
|
||||
Configured in `src-tauri/tauri.conf.json`:
|
||||
|
||||
```json
|
||||
{ "plugins": { "deep-link": { "desktop": { "schemes": ["alphahuman"] } } } }
|
||||
{ "plugins": { "deep-link": { "desktop": { "schemes": ["openhuman"] } } } }
|
||||
```
|
||||
|
||||
## macOS
|
||||
@@ -50,7 +50,7 @@ cp -R src-tauri/target/debug/bundle/macos/tauri-app.app /Applications/
|
||||
open /Applications/tauri-app.app
|
||||
|
||||
# Test deep link
|
||||
open "alphahuman://auth?token=YOUR_TOKEN"
|
||||
open "openhuman://auth?token=YOUR_TOKEN"
|
||||
```
|
||||
|
||||
### Cargo Caching Gotcha
|
||||
@@ -68,9 +68,9 @@ open "alphahuman://auth?token=YOUR_TOKEN"
|
||||
- The macOS WebView (WKWebView) caches aggressively
|
||||
- Clear caches when debugging stale content:
|
||||
```bash
|
||||
rm -rf ~/Library/WebKit/com.alphahuman.app
|
||||
rm -rf ~/Library/Caches/com.alphahuman.app
|
||||
rm -rf ~/Library/Application\ Support/com.alphahuman.app
|
||||
rm -rf ~/Library/WebKit/com.openhuman.app
|
||||
rm -rf ~/Library/Caches/com.openhuman.app
|
||||
rm -rf ~/Library/Application\ Support/com.openhuman.app
|
||||
```
|
||||
|
||||
### Debug Builds: Secondary Instance Behavior
|
||||
|
||||
@@ -213,8 +213,8 @@ npm run tauri build -- --debug --bundles app
|
||||
Clear WebKit cache if needed:
|
||||
|
||||
```bash
|
||||
rm -rf ~/Library/WebKit/com.alphahuman.app
|
||||
rm -rf ~/Library/Caches/com.alphahuman.app
|
||||
rm -rf ~/Library/WebKit/com.openhuman.app
|
||||
rm -rf ~/Library/Caches/com.openhuman.app
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
@@ -31,10 +31,10 @@ Token present
|
||||
|
||||
Two Tauri event listeners run continuously:
|
||||
|
||||
| Event | What it does |
|
||||
|---|---|
|
||||
| `skill-state-changed` | Dispatches `setSkillState` into Redux `skillsSlice.skillStates[skillId]` |
|
||||
| `runtime:skill-status-changed` | Updates `skillsSlice.skills[skillId].status`; surfaces errors |
|
||||
| Event | What it does |
|
||||
| ------------------------------ | ------------------------------------------------------------------------ |
|
||||
| `skill-state-changed` | Dispatches `setSkillState` into Redux `skillsSlice.skillStates[skillId]` |
|
||||
| `runtime:skill-status-changed` | Updates `skillsSlice.skills[skillId].status`; surfaces errors |
|
||||
|
||||
---
|
||||
|
||||
@@ -48,7 +48,8 @@ It is constructed with the user's JWT (`authSlice.token`) and stored as `Arc<Mem
|
||||
in `MemoryState` (a `Mutex<Option<MemoryClientRef>>`).
|
||||
|
||||
Base URL resolution (in priority order):
|
||||
1. `ALPHAHUMAN_BASE_URL` env var
|
||||
|
||||
1. `OPENHUMAN_BASE_URL` env var
|
||||
2. `TINYHUMANS_BASE_URL` env var
|
||||
3. SDK default
|
||||
|
||||
@@ -109,12 +110,12 @@ Examples: `skill:gmail:user@example.com`, `skill:notion:default`.
|
||||
|
||||
**File**: `src-tauri/src/memory/mod.rs`
|
||||
|
||||
| Method | SDK call | When used |
|
||||
|---|---|---|
|
||||
| `store_skill_sync(...)` | `insert_memory` | OAuth complete, periodic sync |
|
||||
| `query_skill_context(...)` | `query_memory` | RAG query — fetch relevant chunks for a user question |
|
||||
| `recall_skill_context(...)` | `recall_memory` | Recall synthesised summary from Master node |
|
||||
| `clear_skill_memory(...)` | `delete_memory` | OAuth revoke / disconnect |
|
||||
| Method | SDK call | When used |
|
||||
| --------------------------- | --------------- | ----------------------------------------------------- |
|
||||
| `store_skill_sync(...)` | `insert_memory` | OAuth complete, periodic sync |
|
||||
| `query_skill_context(...)` | `query_memory` | RAG query — fetch relevant chunks for a user question |
|
||||
| `recall_skill_context(...)` | `recall_memory` | Recall synthesised summary from Master node |
|
||||
| `clear_skill_memory(...)` | `delete_memory` | OAuth revoke / disconnect |
|
||||
|
||||
---
|
||||
|
||||
@@ -141,16 +142,17 @@ chatSend({ threadId, message, model, authToken, backendUrl, messages, notionCont
|
||||
|
||||
Completion events flow back over Tauri events:
|
||||
|
||||
| Event | Frontend handler |
|
||||
|---|---|
|
||||
| `chat:tool_call` | shows active tool indicator |
|
||||
| `chat:tool_result` | clears tool indicator |
|
||||
| `chat:done` | `dispatch(addInferenceResponse(...))` |
|
||||
| `chat:error` | shows error, clears loading state |
|
||||
| Event | Frontend handler |
|
||||
| ------------------ | ------------------------------------- |
|
||||
| `chat:tool_call` | shows active tool indicator |
|
||||
| `chat:tool_result` | clears tool indicator |
|
||||
| `chat:done` | `dispatch(addInferenceResponse(...))` |
|
||||
| `chat:error` | shows error, clears loading state |
|
||||
|
||||
### 5b. Web/Fallback Path
|
||||
|
||||
Used when not running in Tauri (browser). Runs the agentic loop entirely in TypeScript:
|
||||
|
||||
- Calls `inferenceApi.createChatCompletion(request)` directly
|
||||
- Executes tools via `skillManager.callTool(skillId, toolName, args)`
|
||||
- Both paths share the same 5-round `MAX_TOOL_ROUNDS` limit and `{skillId}__{toolName}` naming convention
|
||||
@@ -215,6 +217,7 @@ Step 6: Agentic loop (max 5 rounds)
|
||||
**File**: `src-tauri/src/runtime/qjs_engine.rs` — `call_tool(skill_id, tool_name, args)`
|
||||
|
||||
The Rust runtime routes `call_tool` into the running QuickJS/V8 skill instance:
|
||||
|
||||
- Serialises `args` as JSON
|
||||
- Calls the JS tool handler registered by the skill
|
||||
- Returns `ToolCallResult { content: Vec<ToolContent>, is_error: bool }`
|
||||
@@ -262,14 +265,14 @@ Separately (async, fire-and-forget):
|
||||
|
||||
## Key Files Reference
|
||||
|
||||
| File | Role |
|
||||
|---|---|
|
||||
| `src/providers/SkillProvider.tsx` | Discovery, lifecycle, Redux state sync |
|
||||
| `src/pages/Conversations.tsx` | Message send, both code paths, Notion context |
|
||||
| `src/services/chatService.ts` | `chatSend()`, `chatCancel()`, `useRustChat()` |
|
||||
| `src-tauri/src/commands/chat.rs` | Rust agentic loop, context assembly, tool dispatch |
|
||||
| `src-tauri/src/commands/memory.rs` | `recall_memory` Tauri command |
|
||||
| `src-tauri/src/memory/mod.rs` | `MemoryClient` wrapping tinyhumansai SDK |
|
||||
| `src-tauri/src/runtime/qjs_skill_instance.rs` | Skill sync → memory write triggers |
|
||||
| `src-tauri/src/runtime/qjs_engine.rs` | `discover_skills()`, `call_tool()`, `all_tools()` |
|
||||
| `skills/skills/*/manifest.json` | Skill metadata (git submodule) |
|
||||
| File | Role |
|
||||
| --------------------------------------------- | -------------------------------------------------- |
|
||||
| `src/providers/SkillProvider.tsx` | Discovery, lifecycle, Redux state sync |
|
||||
| `src/pages/Conversations.tsx` | Message send, both code paths, Notion context |
|
||||
| `src/services/chatService.ts` | `chatSend()`, `chatCancel()`, `useRustChat()` |
|
||||
| `src-tauri/src/commands/chat.rs` | Rust agentic loop, context assembly, tool dispatch |
|
||||
| `src-tauri/src/commands/memory.rs` | `recall_memory` Tauri command |
|
||||
| `src-tauri/src/memory/mod.rs` | `MemoryClient` wrapping tinyhumansai SDK |
|
||||
| `src-tauri/src/runtime/qjs_skill_instance.rs` | Skill sync → memory write triggers |
|
||||
| `src-tauri/src/runtime/qjs_engine.rs` | `discover_skills()`, `call_tool()`, `all_tools()` |
|
||||
| `skills/skills/*/manifest.json` | Skill metadata (git submodule) |
|
||||
|
||||
@@ -10,7 +10,7 @@ The Skills System is a Python-based plugin architecture that allows AI agents to
|
||||
|
||||
- Skills modal shows "Setup Failed" with "Skill process exited with code: 1"
|
||||
- Console shows `ModuleNotFoundError: No module named 'pydantic'`
|
||||
- Error paths like `/Users/cyrus/alphahuman/skills/skills/telegram/`
|
||||
- Error paths like `/Users/cyrus/openhuman/skills/skills/telegram/`
|
||||
- Python import failures and subprocess stderr messages
|
||||
|
||||
### Root Cause Analysis
|
||||
@@ -51,7 +51,7 @@ git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
This downloads the skills repository from `https://github.com/alphahumanxyz/skills`.
|
||||
This downloads the skills repository from `https://github.com/openhumanxyz/skills`.
|
||||
|
||||
#### 2. Create Python Virtual Environment
|
||||
|
||||
@@ -87,7 +87,7 @@ This installs:
|
||||
#### Development vs Production Paths
|
||||
|
||||
- **Development**: Skills in git submodule at `./skills/skills/`
|
||||
- **Production**: Skills in `~/.alphahuman/skills/`
|
||||
- **Production**: Skills in `~/.openhuman/skills/`
|
||||
- **Configuration**: `src/lib/skills/paths.ts` handles path resolution
|
||||
|
||||
#### Skill Execution Process
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
## Summary
|
||||
|
||||
- What changed and why.
|
||||
- Keep this to 3-6 bullets focused on user-visible or architecture-impacting changes.
|
||||
|
||||
## Problem
|
||||
|
||||
- What issue or risk this PR addresses.
|
||||
- Include context needed for reviewers to evaluate correctness quickly.
|
||||
|
||||
## Solution
|
||||
|
||||
- How the implementation solves the problem.
|
||||
- Note important design decisions and tradeoffs.
|
||||
|
||||
## Testing
|
||||
|
||||
- [ ] `yarn -s compile`
|
||||
- [ ] `cargo check --manifest-path src-tauri/Cargo.toml`
|
||||
- [ ] Other checks run (list commands)
|
||||
- [ ] Manual validation completed (list scenarios)
|
||||
|
||||
## Impact
|
||||
|
||||
- Runtime/platform impact (desktop/mobile/web/CLI), if any.
|
||||
- Performance, security, migration, or compatibility implications.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- [ ] None
|
||||
- [ ] Yes (describe clearly, including migration steps)
|
||||
|
||||
## Related
|
||||
|
||||
- Issue(s):
|
||||
- Follow-up PR(s)/TODOs:
|
||||
+12
-13
@@ -27,7 +27,7 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24.x
|
||||
cache: "yarn"
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -39,23 +39,22 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
|
||||
- name: Cache Cargo registry
|
||||
# Skip first 7 lines of Cargo.lock (workspace package version bumps) so the key tracks dependency changes only
|
||||
- name: Cargo.lock fingerprint (deps only)
|
||||
id: cargo-lock-fingerprint
|
||||
shell: bash
|
||||
run: |
|
||||
echo "hash=$(tail -n +8 src-tauri/Cargo.lock | openssl dgst -sha256 | awk '{print $2}')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache Cargo registry and git sources
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('src-tauri/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-cargo-registry-${{ steps.cargo-lock-fingerprint.outputs.hash }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-
|
||||
|
||||
- name: Cache Cargo build artifacts
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: src-tauri/target
|
||||
key: ${{ runner.os }}-cargo-target-${{ hashFiles('src-tauri/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-target-
|
||||
${{ runner.os }}-cargo-registry-
|
||||
|
||||
- name: Cache node modules
|
||||
id: yarn-cache
|
||||
@@ -74,6 +73,6 @@ jobs:
|
||||
run: cd skills && yarn install --frozen-lockfile
|
||||
|
||||
- name: Build Tauri app
|
||||
run: yarn tauri build -- --target x86_64-unknown-linux-gnu
|
||||
run: yarn tauri build -- --target x86_64-unknown-linux-gnu -- --bin OpenHuman
|
||||
env:
|
||||
NODE_ENV: production
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
# Standalone macOS Apple Silicon (aarch64) Tauri build — no prepare-release / tagging.
|
||||
#
|
||||
# GitHub: workflow_dispatch checks out the ref. Local act: ACT=true skips checkout (use -b bind + run
|
||||
# ./scripts/run-macos-arm64-build.sh so submodules are initialized before act copies the tree).
|
||||
name: macOS ARM64 build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-macos-arm64:
|
||||
name: Build macOS aarch64 (signed)
|
||||
runs-on: macos-latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.XGH_TOKEN || github.token }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
if: ${{ env.ACT != 'true' }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set Xcode version
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: latest-stable
|
||||
|
||||
- name: Setup Node.js 24.x
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24.x
|
||||
cache: yarn
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: aarch64-apple-darwin
|
||||
|
||||
- name: Cargo.lock fingerprint (deps only)
|
||||
id: cargo-lock-fingerprint
|
||||
shell: bash
|
||||
run: |
|
||||
echo "hash=$(tail -n +8 src-tauri/Cargo.lock | openssl dgst -sha256 | awk '{print $2}')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache Cargo registry and git sources
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: ${{ runner.os }}-cargo-registry-${{ steps.cargo-lock-fingerprint.outputs.hash }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-registry-
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Install skills dependencies
|
||||
run: cd skills && yarn install --frozen-lockfile
|
||||
|
||||
- name: Build skills
|
||||
run: cd skills && yarn build
|
||||
|
||||
- name: Define Tauri configuration overrides
|
||||
id: config-overrides
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
BASE_URL: ${{ vars.BASE_URL }}
|
||||
UPDATER_PUBLIC_KEY: ${{ secrets.UPDATER_PUBLIC_KEY }}
|
||||
WITH_UPDATER: 'true'
|
||||
with:
|
||||
github-token: ${{ secrets.XGH_TOKEN || github.token }}
|
||||
script: |
|
||||
const workspacePath = process.env.GITHUB_WORKSPACE.replace(/\\/g, '/');
|
||||
const prefix = workspacePath.startsWith('/') ? 'file://' : 'file:///';
|
||||
const moduleUrl = `${prefix}${workspacePath}/scripts/prepareTauriConfig.js`;
|
||||
const { default: prepareTauriConfig } = await import(moduleUrl);
|
||||
const config = prepareTauriConfig();
|
||||
core.setOutput('json', JSON.stringify(config));
|
||||
|
||||
- name: Build frontend
|
||||
run: yarn build
|
||||
env:
|
||||
NODE_ENV: production
|
||||
VITE_BACKEND_URL: ${{ vars.VITE_BACKEND_URL }}
|
||||
VITE_SENTRY_DSN: ${{ vars.VITE_SENTRY_DSN }}
|
||||
VITE_DEBUG: ${{ vars.VITE_DEBUG }}
|
||||
|
||||
- name: Build, package (no GitHub release upload)
|
||||
uses: tauri-apps/tauri-action@v0.6.2
|
||||
env:
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
BASE_URL: ${{ vars.BASE_URL }}
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
WITH_UPDATER: 'true'
|
||||
MACOSX_DEPLOYMENT_TARGET: '10.15'
|
||||
with:
|
||||
args: -c ${{ steps.config-overrides.outputs.json }} --target aarch64-apple-darwin -- -- --bin OpenHuman
|
||||
includeDebug: false
|
||||
includeRelease: true
|
||||
includeUpdaterJson: false
|
||||
@@ -17,10 +17,8 @@ on:
|
||||
env:
|
||||
IS_PR: ${{ github.event_name == 'pull_request' }}
|
||||
SHOULD_PUBLISH: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }}
|
||||
PUBLISH_REPO: alphahumanxyz/alphahuman
|
||||
PUBLISH_REPO: openhumanxyz/openhuman
|
||||
XGH_TOKEN: ${{ secrets.XGH_TOKEN }}
|
||||
UPDATER_GIST_URL: ${{ secrets.UPDATER_GIST_URL }}
|
||||
UPDATER_GIST_ID: ${{ secrets.UPDATER_GIST_ID }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
@@ -48,7 +46,7 @@ jobs:
|
||||
run: |
|
||||
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
||||
TAG_NAME="v${PACKAGE_VERSION}"
|
||||
RELEASE_NAME="AlphaHuman v${PACKAGE_VERSION}"
|
||||
RELEASE_NAME="OpenHuman v${PACKAGE_VERSION}"
|
||||
echo "package-version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "tag-name=$TAG_NAME" >> $GITHUB_OUTPUT
|
||||
echo "release-name=$RELEASE_NAME" >> $GITHUB_OUTPUT
|
||||
@@ -162,15 +160,15 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- platform: "macos-latest"
|
||||
args: "--target aarch64-apple-darwin"
|
||||
target: "aarch64-apple-darwin"
|
||||
- platform: "macos-latest"
|
||||
args: "--target x86_64-apple-darwin"
|
||||
target: "x86_64-apple-darwin"
|
||||
- platform: "ubuntu-22.04"
|
||||
args: ""
|
||||
target: ""
|
||||
- platform: 'macos-latest'
|
||||
args: '--target aarch64-apple-darwin'
|
||||
target: 'aarch64-apple-darwin'
|
||||
- platform: 'macos-latest'
|
||||
args: '--target x86_64-apple-darwin'
|
||||
target: 'x86_64-apple-darwin'
|
||||
- platform: 'ubuntu-22.04'
|
||||
args: ''
|
||||
target: ''
|
||||
runs-on: ${{ matrix.settings.platform }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -191,7 +189,7 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24.x
|
||||
cache: "yarn"
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -287,20 +285,13 @@ jobs:
|
||||
env:
|
||||
NODE_ENV: production
|
||||
VITE_BACKEND_URL: ${{ vars.VITE_BACKEND_URL }}
|
||||
VITE_TELEGRAM_BOT_USERNAME: ${{ secrets.VITE_TELEGRAM_BOT_USERNAME }}
|
||||
VITE_TELEGRAM_BOT_ID: ${{ secrets.VITE_TELEGRAM_BOT_ID }}
|
||||
VITE_TELEGRAM_API_ID: ${{ secrets.VITE_TELEGRAM_API_ID }}
|
||||
VITE_TELEGRAM_API_HASH: ${{ secrets.VITE_TELEGRAM_API_HASH }}
|
||||
VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }}
|
||||
VITE_SKILLS_GITHUB_REPO: ${{ vars.VITE_SKILLS_GITHUB_REPO }}
|
||||
VITE_DEBUG: ${{ vars.VITE_DEBUG }}
|
||||
|
||||
- name: Build, package and publish
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
uses: tauri-apps/tauri-action@v0.6.2
|
||||
id: build-tauri
|
||||
env:
|
||||
TELEGRAM_API_ID: ${{ secrets.VITE_TELEGRAM_API_ID }}
|
||||
TELEGRAM_API_HASH: ${{ secrets.VITE_TELEGRAM_API_HASH }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
@@ -314,14 +305,14 @@ jobs:
|
||||
# macOS 10.15+ required for std::filesystem used by llama.cpp
|
||||
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }}
|
||||
with:
|
||||
args: "-c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}"
|
||||
args: '-c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }} -- -- --bin OpenHuman'
|
||||
includeDebug: ${{ needs.get-version.outputs.should-publish == '' && inputs.forceRelease != 'true' }}
|
||||
includeRelease: ${{ needs.get-version.outputs.should-publish != '' || inputs.forceRelease == 'true' }}
|
||||
# TDLib dylibs are now bundled natively via build.rs + tauri.conf.json macOS.frameworks
|
||||
# No post-build scripts needed - Tauri bundler handles copying and signing
|
||||
releaseId: ${{ needs.create-release.outputs.releaseId }}
|
||||
owner: alphahumanxyz
|
||||
repo: alphahuman
|
||||
owner: openhumanxyz
|
||||
repo: openhuman
|
||||
|
||||
- name: Get file info
|
||||
id: file-info
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
name: PR Protection - Main Branch
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check-pr-protection:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check PR target branch
|
||||
id: check-target
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const pr = context.payload.pull_request;
|
||||
const baseBranch = pr.base.ref;
|
||||
const headBranch = pr.head.ref;
|
||||
const prAuthor = pr.user.login;
|
||||
const prTitle = pr.title;
|
||||
const prBody = pr.body || '';
|
||||
|
||||
// Check if PR is targeting main
|
||||
const isTargetingMain = baseBranch === 'main';
|
||||
|
||||
if (!isTargetingMain) {
|
||||
console.log(`PR is targeting ${baseBranch}, not main. Skipping protection check.`);
|
||||
core.setOutput('needs_check', 'false');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`PR #${pr.number} is targeting ${baseBranch}`);
|
||||
console.log(`PR author: ${prAuthor}`);
|
||||
console.log(`PR title: ${prTitle}`);
|
||||
console.log(`Head branch: ${headBranch}`);
|
||||
|
||||
// Check if PR title follows conventional commit format
|
||||
// Allowed prefixes: feat, fix, chore, refactor, docs, test, style, perf, revert
|
||||
const conventionalCommitPattern = /^(feat|fix|chore|refactor|docs|test|style|perf|revert)(\(.+\))?: .+/;
|
||||
const followsConventionalFormat = conventionalCommitPattern.test(prTitle);
|
||||
|
||||
console.log(`Conventional commit format check: ${followsConventionalFormat ? 'PASSED' : 'FAILED'}`);
|
||||
if (!followsConventionalFormat) {
|
||||
console.log(`PR title must follow conventional commit format: <type>: <description>`);
|
||||
console.log(`Allowed types: feat, fix, chore, refactor, docs, test, style, perf, revert`);
|
||||
}
|
||||
|
||||
// Check if this is the automated PR from create-develop-to-main-pr workflow
|
||||
// The automated PR has these characteristics:
|
||||
// 1. Created by github-actions[bot]
|
||||
// 2. From develop branch to main
|
||||
// 3. Title matches pattern: "chore: merge develop into main (vX.Y.Z)"
|
||||
// 4. Body contains "This PR automatically merges changes from develop into main"
|
||||
|
||||
// Validate PR title matches expected pattern: "chore: merge develop into main" followed by optional version
|
||||
const expectedTitlePattern = /^chore: merge develop into main( \(v\d+\.\d+\.\d+\))?$/;
|
||||
const titleMatches = expectedTitlePattern.test(prTitle);
|
||||
|
||||
console.log(`Automated PR title validation: ${titleMatches ? 'PASSED' : 'FAILED'}`);
|
||||
console.log(`Expected pattern: "chore: merge develop into main" or "chore: merge develop into main (vX.Y.Z)"`);
|
||||
|
||||
const isAutomatedPR =
|
||||
prAuthor === 'github-actions[bot]' &&
|
||||
headBranch === 'develop' &&
|
||||
titleMatches &&
|
||||
prBody.includes('This PR automatically merges changes from develop into main');
|
||||
|
||||
if (isAutomatedPR) {
|
||||
console.log('This PR is from the automated workflow. Allowing it.');
|
||||
core.setOutput('needs_check', 'false');
|
||||
core.setOutput('is_allowed', 'true');
|
||||
} else {
|
||||
console.log('This PR is NOT from the automated workflow.');
|
||||
|
||||
// Even if not automated, check if title follows conventional commit format
|
||||
if (!followsConventionalFormat) {
|
||||
console.log('PR title does not follow conventional commit format. Blocking it.');
|
||||
core.setOutput('needs_check', 'true');
|
||||
core.setOutput('is_allowed', 'false');
|
||||
core.setOutput('conventional_format_failed', 'true');
|
||||
} else {
|
||||
console.log('PR title follows conventional commit format, but PR is not from automated workflow. Blocking it.');
|
||||
core.setOutput('needs_check', 'true');
|
||||
core.setOutput('is_allowed', 'false');
|
||||
core.setOutput('conventional_format_failed', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
// Store the conventional format check result
|
||||
core.setOutput('conventional_format', followsConventionalFormat ? 'true' : 'false');
|
||||
|
||||
- name: Block unauthorized PR to main
|
||||
if: steps.check-target.outputs.needs_check == 'true' && steps.check-target.outputs.is_allowed == 'false'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const pr = context.payload.pull_request;
|
||||
const baseBranch = pr.base.ref;
|
||||
const prAuthor = pr.user.login;
|
||||
const prTitle = pr.title;
|
||||
const headBranch = pr.head.ref;
|
||||
const prBody = pr.body || '';
|
||||
|
||||
// Check which validation criteria failed
|
||||
const conventionalCommitPattern = /^(feat|fix|chore|refactor|docs|test|style|perf|revert)(\(.+\))?: .+/;
|
||||
const followsConventionalFormat = conventionalCommitPattern.test(prTitle);
|
||||
|
||||
const checks = {
|
||||
author: prAuthor === 'github-actions[bot]',
|
||||
branch: headBranch === 'develop',
|
||||
automatedTitle: /^chore: merge develop into main( \(v\d+\.\d+\.\d+\))?$/.test(prTitle),
|
||||
body: prBody.includes('This PR automatically merges changes from develop into main'),
|
||||
conventionalFormat: followsConventionalFormat
|
||||
};
|
||||
|
||||
const failedChecks = Object.entries(checks)
|
||||
.filter(([_, passed]) => !passed)
|
||||
.map(([check]) => check);
|
||||
|
||||
console.log('Validation checks:', JSON.stringify(checks, null, 2));
|
||||
console.log('Failed checks:', failedChecks.join(', '));
|
||||
|
||||
// Build detailed error message
|
||||
let errorDetails = '';
|
||||
if (failedChecks.length > 0) {
|
||||
errorDetails = `\n\n**Failed validation checks:**\n`;
|
||||
if (!checks.author) errorDetails += `- ❌ Author must be \`github-actions[bot]\` (found: \`${prAuthor}\`)\n`;
|
||||
if (!checks.branch) errorDetails += `- ❌ Head branch must be \`develop\` (found: \`${headBranch}\`)\n`;
|
||||
if (!checks.automatedTitle) errorDetails += `- ❌ Title must match pattern: \`chore: merge develop into main\` or \`chore: merge develop into main (vX.Y.Z)\` (found: \`${prTitle}\`)\n`;
|
||||
if (!checks.body) errorDetails += `- ❌ Body must contain: "This PR automatically merges changes from develop into main"\n`;
|
||||
if (!checks.conventionalFormat) errorDetails += `- ❌ PR title must follow conventional commit format: \`<type>: <description>\`\n`;
|
||||
if (!checks.conventionalFormat) errorDetails += ` Allowed types: \`feat\`, \`fix\`, \`chore\`, \`refactor\`, \`docs\`, \`test\`, \`style\`, \`perf\`, \`revert\`\n`;
|
||||
if (!checks.conventionalFormat) errorDetails += ` Example: \`feat: add new authentication endpoint\`\n`;
|
||||
}
|
||||
|
||||
// Comment on the PR explaining why it was blocked
|
||||
const codeBlock = '`';
|
||||
const commentBody = [
|
||||
'## PR Protection Rule Violation',
|
||||
'',
|
||||
`This PR targets the ${codeBlock}${baseBranch}${codeBlock} branch, which is protected.`,
|
||||
'',
|
||||
`**Only automated PRs from the ${codeBlock}create-develop-to-main-pr.yml${codeBlock} workflow are allowed to target ${codeBlock}${baseBranch}${codeBlock}.**${errorDetails}`,
|
||||
'',
|
||||
`**To merge changes into ${codeBlock}${baseBranch}${codeBlock}:**`,
|
||||
`1. Create your PR targeting the ${codeBlock}develop${codeBlock} branch instead`,
|
||||
`2. Once merged to ${codeBlock}develop${codeBlock}, the automated workflow will create a PR from ${codeBlock}develop${codeBlock} to ${codeBlock}${baseBranch}${codeBlock}`,
|
||||
'',
|
||||
`Please update this PR to target ${codeBlock}develop${codeBlock} instead, or close it and create a new PR targeting ${codeBlock}develop${codeBlock}.`
|
||||
].join('\n');
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: commentBody
|
||||
});
|
||||
|
||||
// Fail the workflow to block the PR
|
||||
let failureMessage = `PR #${pr.number} cannot target ${baseBranch} branch. `;
|
||||
|
||||
if (!checks.conventionalFormat) {
|
||||
failureMessage += `PR title does not follow conventional commit format. `;
|
||||
}
|
||||
|
||||
failureMessage += `Failed checks: ${failedChecks.join(', ')}. `;
|
||||
failureMessage += `Only automated PRs from create-develop-to-main-pr.yml workflow are allowed.`;
|
||||
|
||||
core.setFailed(failureMessage);
|
||||
+145
-22
@@ -23,6 +23,7 @@ jobs:
|
||||
prepare-release:
|
||||
name: Prepare release commit and tag
|
||||
runs-on: ubuntu-latest
|
||||
environment: Production
|
||||
outputs:
|
||||
version: ${{ steps.bump.outputs.version }}
|
||||
tag: ${{ steps.bump.outputs.tag }}
|
||||
@@ -158,6 +159,7 @@ jobs:
|
||||
create-release:
|
||||
name: Create GitHub release
|
||||
runs-on: ubuntu-latest
|
||||
environment: Production
|
||||
needs: prepare-release
|
||||
outputs:
|
||||
release_id: ${{ steps.create.outputs.release_id }}
|
||||
@@ -202,16 +204,24 @@ jobs:
|
||||
name: Build and upload artifacts
|
||||
needs: [prepare-release, create-release]
|
||||
runs-on: ${{ matrix.settings.platform }}
|
||||
environment: Production
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- platform: macos-latest
|
||||
args: --target aarch64-apple-darwin
|
||||
- platform: macos-latest
|
||||
args: --target x86_64-apple-darwin
|
||||
# macOS builds are disabled for now to ensure the flow works first
|
||||
# - platform: macos-latest
|
||||
# args: --target aarch64-apple-darwin
|
||||
# target: aarch64-apple-darwin
|
||||
# artifact_suffix: aarch64-apple-darwin
|
||||
# - platform: macos-latest
|
||||
# args: --target x86_64-apple-darwin
|
||||
# target: x86_64-apple-darwin
|
||||
# artifact_suffix: x86_64-apple-darwin
|
||||
- platform: ubuntu-22.04
|
||||
args: ""
|
||||
args: ''
|
||||
target: ''
|
||||
artifact_suffix: ubuntu
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
@@ -245,9 +255,29 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
|
||||
# Skip first 7 lines of Cargo.lock (workspace package version bumps) so the key tracks dependency changes only
|
||||
- name: Cargo.lock fingerprint (deps only)
|
||||
id: cargo-lock-fingerprint
|
||||
shell: bash
|
||||
run: |
|
||||
echo "hash=$(tail -n +8 src-tauri/Cargo.lock | openssl dgst -sha256 | awk '{print $2}')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache Cargo registry and git sources
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: ${{ runner.os }}-cargo-registry-${{ steps.cargo-lock-fingerprint.outputs.hash }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-registry-
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Install skills dependencies
|
||||
run: cd skills && yarn install --frozen-lockfile
|
||||
|
||||
- name: Build skills
|
||||
run: cd skills && yarn build
|
||||
|
||||
@@ -257,7 +287,7 @@ jobs:
|
||||
env:
|
||||
BASE_URL: ${{ vars.BASE_URL }}
|
||||
UPDATER_PUBLIC_KEY: ${{ secrets.UPDATER_PUBLIC_KEY }}
|
||||
WITH_UPDATER: "true"
|
||||
WITH_UPDATER: 'true'
|
||||
with:
|
||||
script: |
|
||||
const workspacePath = process.env.GITHUB_WORKSPACE.replace(/\\/g, '/');
|
||||
@@ -272,34 +302,127 @@ jobs:
|
||||
env:
|
||||
NODE_ENV: production
|
||||
VITE_BACKEND_URL: ${{ vars.VITE_BACKEND_URL }}
|
||||
VITE_TELEGRAM_BOT_USERNAME: ${{ secrets.VITE_TELEGRAM_BOT_USERNAME }}
|
||||
VITE_TELEGRAM_BOT_ID: ${{ secrets.VITE_TELEGRAM_BOT_ID }}
|
||||
VITE_TELEGRAM_API_ID: ${{ secrets.VITE_TELEGRAM_API_ID }}
|
||||
VITE_TELEGRAM_API_HASH: ${{ secrets.VITE_TELEGRAM_API_HASH }}
|
||||
VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }}
|
||||
VITE_SKILLS_GITHUB_REPO: ${{ vars.VITE_SKILLS_GITHUB_REPO }}
|
||||
VITE_SENTRY_DSN: ${{ vars.VITE_SENTRY_DSN }}
|
||||
VITE_DEBUG: ${{ vars.VITE_DEBUG }}
|
||||
|
||||
- name: Build, package and upload to release
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
uses: tauri-apps/tauri-action@v0.6.2
|
||||
id: tauri-build
|
||||
env:
|
||||
TELEGRAM_API_ID: ${{ secrets.VITE_TELEGRAM_API_ID }}
|
||||
TELEGRAM_API_HASH: ${{ secrets.VITE_TELEGRAM_API_HASH }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
BASE_URL: ${{ vars.BASE_URL }}
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.UPDATER_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.UPDATER_PRIVATE_KEY_PASSWORD }}
|
||||
WITH_UPDATER: "true"
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY || secrets.UPDATER_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD || secrets.UPDATER_PRIVATE_KEY_PASSWORD }}
|
||||
WITH_UPDATER: 'true'
|
||||
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }}
|
||||
with:
|
||||
args: -c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}
|
||||
# Tools discovery now uses a JS mock registry (no Rust discovery
|
||||
# binary target), so there is no extra helper executable for Tauri
|
||||
# to copy/sign inside release app bundles.
|
||||
# Restrict Cargo bin selection for the Tauri bundle build so only
|
||||
# the desktop UI app binary is packaged.
|
||||
# Yarn v1 strips one "--" layer when invoking scripts, hence the
|
||||
# double-separator when forwarding flags to Cargo.
|
||||
args: -c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }} -- -- --bin OpenHuman
|
||||
includeDebug: false
|
||||
includeRelease: true
|
||||
releaseId: ${{ needs.create-release.outputs.release_id }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
owner: tinyhumansai
|
||||
repo: openhuman
|
||||
|
||||
- name: Verify macOS app bundle excludes standalone core binary
|
||||
if: matrix.settings.platform == 'macos-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
APP_PATH="src-tauri/target/${{ matrix.settings.target }}/release/bundle/macos/OpenHuman.app"
|
||||
echo "Inspecting bundle at: $APP_PATH"
|
||||
ls -la "$APP_PATH/Contents/MacOS"
|
||||
if [ -f "$APP_PATH/Contents/MacOS/openhuman-core" ]; then
|
||||
echo "Unexpected standalone binary found inside app bundle: openhuman-core"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Build standalone CLI binaries
|
||||
shell: bash
|
||||
run: |
|
||||
CARGO_TARGET=""
|
||||
if [ -n "$MATRIX_TARGET" ]; then
|
||||
CARGO_TARGET="--target $MATRIX_TARGET"
|
||||
fi
|
||||
cargo build --manifest-path src-tauri/Cargo.toml --release --features standalone-bins $CARGO_TARGET --bin openhuman-core --bin openhuman-cli
|
||||
env:
|
||||
MATRIX_TARGET: ${{ matrix.settings.target }}
|
||||
|
||||
- name: Resolve standalone CLI artifact paths
|
||||
id: cli-paths
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "$MATRIX_TARGET" ]; then
|
||||
BASE_DIR="src-tauri/target/$MATRIX_TARGET/release"
|
||||
else
|
||||
BASE_DIR="src-tauri/target/release"
|
||||
fi
|
||||
echo "base_dir=$BASE_DIR" >> "$GITHUB_OUTPUT"
|
||||
echo "core_path=$BASE_DIR/openhuman-core" >> "$GITHUB_OUTPUT"
|
||||
echo "cli_path=$BASE_DIR/openhuman-cli" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
MATRIX_TARGET: ${{ matrix.settings.target }}
|
||||
|
||||
- name: Upload standalone CLI artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: standalone-bins-${{ matrix.settings.platform }}-${{ matrix.settings.artifact_suffix }}
|
||||
path: |
|
||||
${{ steps.cli-paths.outputs.core_path }}
|
||||
${{ steps.cli-paths.outputs.cli_path }}
|
||||
|
||||
cleanup-failed-release:
|
||||
name: Remove release and tag if build failed
|
||||
runs-on: ubuntu-latest
|
||||
environment: Production
|
||||
needs: [prepare-release, create-release, build-artifacts]
|
||||
if: always() && needs.create-release.result == 'success' && (needs.build-artifacts.result == 'failure' || needs.build-artifacts.result == 'cancelled')
|
||||
steps:
|
||||
- name: Delete GitHub release
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const releaseId = Number('${{ needs.create-release.outputs.release_id }}');
|
||||
|
||||
if (!Number.isFinite(releaseId) || releaseId <= 0) {
|
||||
core.setFailed('Invalid or missing release_id; cannot delete release.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await github.rest.repos.deleteRelease({ owner, repo, release_id: releaseId });
|
||||
core.info(`Deleted release ${releaseId}`);
|
||||
} catch (e) {
|
||||
core.warning(`deleteRelease failed: ${e.message}`);
|
||||
}
|
||||
|
||||
- name: Delete remote tag
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const tag = '${{ needs.prepare-release.outputs.tag }}';
|
||||
|
||||
try {
|
||||
await github.rest.git.deleteRef({ owner, repo, ref: `tags/${tag}` });
|
||||
core.info(`Deleted remote tag ${tag}`);
|
||||
} catch (e) {
|
||||
if (e.status === 404) {
|
||||
core.info(`Tag ${tag} already absent on remote`);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24.x
|
||||
cache: "yarn"
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Cache node modules
|
||||
id: yarn-cache
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@ name: Update Changelog
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -155,7 +155,7 @@ jobs:
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
output_lines.append(line)
|
||||
|
||||
|
||||
# Check if this is the [Unreleased] header line
|
||||
if line.strip() == "## [Unreleased]":
|
||||
# Find the end of the [Unreleased] section (next ## header or end of file)
|
||||
@@ -169,7 +169,7 @@ jobs:
|
||||
inserted = True
|
||||
# Continue with remaining lines
|
||||
continue
|
||||
|
||||
|
||||
i += 1
|
||||
|
||||
# If [Unreleased] not found, prepend
|
||||
@@ -1,71 +0,0 @@
|
||||
name: Version Bump (Legacy)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
version-bump:
|
||||
runs-on: ubuntu-latest
|
||||
environment: Production
|
||||
# Skip if this is a version bump commit to avoid infinite loop
|
||||
if: "!contains(github.event.head_commit.message, 'chore: bump version')"
|
||||
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
id: app-token
|
||||
uses: tibdex/github-app-token@v1
|
||||
with:
|
||||
app_id: ${{ secrets.XGITHUB_APP_ID }}
|
||||
private_key: ${{ secrets.XGITHUB_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Use GitHub App token for checkout and push operations
|
||||
# This token has bypass permissions if the GitHub App is configured with them
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Configure Git
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
# Update remote URL to use GitHub App token for all git operations
|
||||
git remote set-url origin https://${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git
|
||||
|
||||
- name: Pull latest changes
|
||||
run: |
|
||||
# Ensure we're on main and pull latest changes to avoid push conflicts
|
||||
git checkout main
|
||||
git pull origin main --ff-only
|
||||
|
||||
- name: Bump version
|
||||
id: version
|
||||
run: |
|
||||
# Get current version
|
||||
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
||||
echo "Current version: $CURRENT_VERSION"
|
||||
|
||||
# Bump minor version (creates commit and tag)
|
||||
# The commit message includes [skip ci] to prevent triggering this workflow again
|
||||
NEW_VERSION=$(npm version minor -m "chore: bump version to %s" | sed 's/v//')
|
||||
echo "New version: $NEW_VERSION"
|
||||
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Push changes
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: |
|
||||
# Push to main and tags using GitHub App token (remote URL already configured)
|
||||
git push origin main
|
||||
git push origin --tags
|
||||
@@ -48,3 +48,6 @@ e2e-results/
|
||||
wdio-logs/
|
||||
test-results/
|
||||
coverage/
|
||||
|
||||
tauri.key
|
||||
tauri.key.pub
|
||||
|
||||
+31
-31
@@ -1,37 +1,37 @@
|
||||
# #!/usr/bin/env sh
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# # Run format check first (capture exit code without breaking script)
|
||||
# set +e
|
||||
# yarn format:check
|
||||
# FORMAT_EXIT=$?
|
||||
# set -e
|
||||
# Run format check first (capture exit code without breaking script)
|
||||
set +e
|
||||
yarn format:check
|
||||
FORMAT_EXIT=$?
|
||||
set -e
|
||||
|
||||
# # If format check failed, run format to auto-fix
|
||||
# if [ $FORMAT_EXIT -ne 0 ]; then
|
||||
# echo "Formatting issues detected. Running format to auto-fix..."
|
||||
# yarn format
|
||||
# fi
|
||||
# If format check failed, run format to auto-fix
|
||||
if [ $FORMAT_EXIT -ne 0 ]; then
|
||||
echo "Formatting issues detected. Running format to auto-fix..."
|
||||
yarn format
|
||||
fi
|
||||
|
||||
# # Run lint check (capture exit code without breaking script)
|
||||
# set +e
|
||||
# yarn lint
|
||||
# LINT_EXIT=$?
|
||||
# set -e
|
||||
# Run lint check (capture exit code without breaking script)
|
||||
set +e
|
||||
yarn lint
|
||||
LINT_EXIT=$?
|
||||
set -e
|
||||
|
||||
# # If lint check failed, run lint:fix to auto-fix
|
||||
# if [ $LINT_EXIT -ne 0 ]; then
|
||||
# echo "Linting issues detected. Running lint:fix to auto-fix..."
|
||||
# yarn lint:fix
|
||||
# fi
|
||||
# If lint check failed, run lint:fix to auto-fix
|
||||
if [ $LINT_EXIT -ne 0 ]; then
|
||||
echo "Linting issues detected. Running lint:fix to auto-fix..."
|
||||
yarn lint:fix
|
||||
fi
|
||||
|
||||
# # Run TypeScript compile check (capture exit code without breaking script)
|
||||
# set +e
|
||||
# yarn compile
|
||||
# COMPILE_EXIT=$?
|
||||
# set -e
|
||||
# Run TypeScript compile check (capture exit code without breaking script)
|
||||
set +e
|
||||
yarn compile
|
||||
COMPILE_EXIT=$?
|
||||
set -e
|
||||
|
||||
# # Exit with error if any command still fails after fixes
|
||||
# if [ $FORMAT_EXIT -ne 0 ] || [ $LINT_EXIT -ne 0 ] || [ $COMPILE_EXIT -ne 0 ]; then
|
||||
# echo "Pre-push checks failed. Please fix format, lint, and/or TypeScript errors before pushing."
|
||||
# exit 1
|
||||
# fi
|
||||
# Exit with error if any command still fails after fixes
|
||||
if [ $FORMAT_EXIT -ne 0 ] || [ $LINT_EXIT -ne 0 ] || [ $COMPILE_EXIT -ne 0 ]; then
|
||||
echo "Pre-push checks failed. Please fix format, lint, and/or TypeScript errors before pushing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -51,7 +51,7 @@ yarn dev:app
|
||||
yarn tauri build
|
||||
|
||||
# Debug build with .app bundle (required for deep link testing on macOS)
|
||||
# On macOS, alphahuman:// only works when running the .app, not `tauri dev`
|
||||
# On macOS, openhuman:// only works when running the .app, not `tauri dev`
|
||||
yarn tauri build --debug --bundles app
|
||||
yarn macos:dev
|
||||
|
||||
@@ -133,10 +133,10 @@ Model Context Protocol implementation for AI tool execution over Socket.io:
|
||||
|
||||
### Deep Link Auth Flow
|
||||
|
||||
Web-to-desktop handoff using `alphahuman://` URL scheme:
|
||||
Web-to-desktop handoff using `openhuman://` URL scheme:
|
||||
|
||||
1. User authenticates in browser
|
||||
2. Browser redirects to `alphahuman://auth?token=<loginToken>`
|
||||
2. Browser redirects to `openhuman://auth?token=<loginToken>`
|
||||
3. Tauri catches the deep link, Rust `exchange_token` command calls backend via `reqwest` (bypasses CORS)
|
||||
4. Backend returns `sessionToken` + user object
|
||||
5. App stores session in Redux, navigates to onboarding/home
|
||||
@@ -209,22 +209,18 @@ Advanced JavaScript execution engine for skills using V8 (via deno_core):
|
||||
|
||||
Set in `.env` (Vite exposes `VITE_*` prefixed vars):
|
||||
|
||||
| Variable | Purpose |
|
||||
| ---------------------------- | ------------------------------------------------------------------- |
|
||||
| `VITE_BACKEND_URL` | Backend API URL (default: `http://localhost:5005`) |
|
||||
| `VITE_TELEGRAM_API_ID` | Telegram MTProto API ID |
|
||||
| `VITE_TELEGRAM_API_HASH` | Telegram MTProto API hash |
|
||||
| `VITE_TELEGRAM_BOT_USERNAME` | Telegram bot username |
|
||||
| `VITE_TELEGRAM_BOT_ID` | Telegram bot numeric ID |
|
||||
| `VITE_SENTRY_DSN` | Sentry DSN for error reporting (optional) |
|
||||
| `VITE_DEBUG` | Debug mode flag |
|
||||
| `ALPHAHUMAN_DAEMON_INTERNAL` | Force internal daemon mode (default: false, uses external services) |
|
||||
| Variable | Purpose |
|
||||
| --------------------------- | ------------------------------------------------------------------- |
|
||||
| `VITE_BACKEND_URL` | Backend API URL (default: `http://localhost:5005`) |
|
||||
| `VITE_SENTRY_DSN` | Sentry DSN for error reporting (optional) |
|
||||
| `VITE_DEBUG` | Debug mode flag |
|
||||
| `OPENHUMAN_DAEMON_INTERNAL` | Force internal daemon mode (default: false, uses external services) |
|
||||
|
||||
Production defaults are in `src/utils/config.ts`.
|
||||
|
||||
## AI Configuration System
|
||||
|
||||
AlphaHuman uses an OpenClaw-compliant AI configuration system that automatically injects persona and tool context into every user message for consistent AI behavior.
|
||||
OpenHumanuses an OpenClaw-compliant AI configuration system that automatically injects persona and tool context into every user message for consistent AI behavior.
|
||||
|
||||
### Configuration Files
|
||||
|
||||
@@ -283,7 +279,7 @@ const toolsMessage = await injectTools(userMessage);
|
||||
|
||||
```
|
||||
[PERSONA_CONTEXT]
|
||||
I am AlphaHuman: that incredibly smart, funny friend who loves helping people get stuff done
|
||||
I am OpenHuman that incredibly smart, funny friend who loves helping people get stuff done
|
||||
Personality: Curious & Enthusiastic, Witty & Engaging, Empathetic
|
||||
Voice: Conversational, Use humor naturally but don't force it
|
||||
[/PERSONA_CONTEXT]
|
||||
@@ -410,9 +406,9 @@ Key updates from recent commits (cd9ebcd to current):
|
||||
- Session capture and transcript management
|
||||
- Memory chunking and context formatting
|
||||
- **Enhanced CI/CD Pipeline** (`b1d7bce`): Production-ready deployment
|
||||
- XGH_TOKEN authentication for alphahumanxyz/alphahuman releases
|
||||
- XGH_TOKEN authentication for openhumanxyz/openhuman releases
|
||||
- Python sidecar setup and caching for cross-platform builds
|
||||
- Tauri configuration updates (com.alphahuman.app identifier)
|
||||
- Tauri configuration updates (com.openhuman.app identifier)
|
||||
- GitHub Pages deployment with optimized workflows
|
||||
- Version tagging and environment variable management
|
||||
- **Device Detection & Download System** (`9d74721`, `b5bccd2`): Enhanced multi-architecture download support
|
||||
@@ -467,9 +463,11 @@ Key updates from recent commits (cd9ebcd to current):
|
||||
|
||||
## Git Workflow
|
||||
|
||||
- **Push target**: All pushes go to the **user's private repo** (your fork). Do not push directly to the org repository.
|
||||
- **PR target**: All pull requests are opened **from your fork** against the **org's private repo**, targeting the **`develop`** branch (not `main`).
|
||||
- **No direct pushes to org**: The org repo does not allow direct pushes. All changes reach the org repo via PRs from your fork.
|
||||
- **Repository visibility**: The project is public.
|
||||
- **Push target**: Pushes should go to your working branch in the public repository (or your fork if your access model requires it).
|
||||
- **PR target**: Open pull requests against the public upstream repository, targeting the **`main`** branch.
|
||||
- **PR template required**: Use `.github/pull_request_template.md` for all pull requests.
|
||||
- **AI tooling rule**: Any AI-generated PR description must follow the template sections in order and keep all checklist items.
|
||||
|
||||
## Key Patterns
|
||||
|
||||
@@ -500,7 +498,7 @@ Key updates from recent commits (cd9ebcd to current):
|
||||
|
||||
## Platform Gotchas
|
||||
|
||||
- **macOS deep links**: Require `.app` bundle (not `tauri dev`). Clear WebKit caches when debugging stale content: `rm -rf ~/Library/WebKit/com.alphahuman.app ~/Library/Caches/com.alphahuman.app`
|
||||
- **macOS deep links**: Require `.app` bundle (not `tauri dev`). Clear WebKit caches when debugging stale content: `rm -rf ~/Library/WebKit/com.openhuman.app ~/Library/Caches/com.openhuman.app`
|
||||
- **Cargo caching**: May serve stale frontend assets on incremental builds. Run `cargo clean --manifest-path src-tauri/Cargo.toml` if the app shows outdated UI.
|
||||
- **`window.__TAURI__`**: Not available at module load time. Use static imports and try/catch around Tauri API calls (not around imports).
|
||||
- **Android background services**: RuntimeService requires notification permissions (API 33+) and foreground service type specification (API 34+). Use Android logging (`android_logger`) for debug output in logcat.
|
||||
|
||||
+9
-9
@@ -1,4 +1,4 @@
|
||||
# Contributing to AlphaHuman
|
||||
# Contributing to OpenHuman
|
||||
|
||||
Thank you for your interest in contributing. This document explains how to get set up, follow our workflow, and submit changes.
|
||||
|
||||
@@ -19,7 +19,7 @@ This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDU
|
||||
## Getting Started
|
||||
|
||||
- Read the [README](README.md) and [ARCHITECTURE](ARCHITECTURE.md) for context.
|
||||
- Check [open issues](https://github.com/alphahumanxyz/alphahuman/issues) and discussions for ideas and to avoid duplicate work.
|
||||
- Check [open issues](https://github.com/tinyhumansai/openhuman/issues) and discussions for ideas and to avoid duplicate work.
|
||||
- For security issues, see [SECURITY.md](SECURITY.md) — do not report vulnerabilities in public issues.
|
||||
|
||||
## Development Setup
|
||||
@@ -33,8 +33,8 @@ This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDU
|
||||
### Clone and Install
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YOUR_USERNAME/alphahuman.git
|
||||
cd alphahuman
|
||||
git clone https://github.com/YOUR_USERNAME/openhuman.git
|
||||
cd openhuman
|
||||
yarn install
|
||||
```
|
||||
|
||||
@@ -55,7 +55,7 @@ Copy or create a `.env` from the documented template and set `VITE_BACKEND_URL`,
|
||||
|
||||
## Git Workflow
|
||||
|
||||
- **Fork** the [alphahuman](https://github.com/alphahumanxyz/alphahuman) repository and work in your fork.
|
||||
- **Fork** the [openhuman](https://github.com/tinyhumansai/openhuman) repository and work in your fork.
|
||||
- **Base branch**: All pull requests must target the **`develop`** branch (not `main`).
|
||||
- **No direct pushes** to the organization repo; all changes come in via pull requests from forks.
|
||||
|
||||
@@ -69,7 +69,7 @@ Use short, descriptive branches, e.g.:
|
||||
|
||||
## Making Changes
|
||||
|
||||
1. Create a branch from `develop`:
|
||||
1. Create a branch from `develop`:
|
||||
`git checkout develop && git pull origin develop && git checkout -b fix/your-change`
|
||||
2. Make your changes. Keep commits focused and messages clear (e.g., “Fix socket reconnect on network drop”).
|
||||
3. Follow our [project conventions](#project-conventions) and run checks before pushing.
|
||||
@@ -85,9 +85,9 @@ Pre-commit/pre-push hooks (Husky) run formatting and linting; fix any failures b
|
||||
|
||||
## Submitting Changes
|
||||
|
||||
1. Push your branch to your fork:
|
||||
1. Push your branch to your fork:
|
||||
`git push origin fix/your-change`
|
||||
2. Open a **pull request** against **`develop`** in the [alphahuman](https://github.com/alphahumanxyz/alphahuman) repository.
|
||||
2. Open a **pull request** against **`develop`** in the [openhuman](https://github.com/tinyhumansai/openhuman) repository.
|
||||
3. Fill in the PR template (if present): describe what changed, why, and how to test.
|
||||
4. Link any related issues (e.g., “Fixes #123”).
|
||||
5. Address review feedback and keep the PR up to date with `develop` (rebase or merge as the project prefers).
|
||||
@@ -108,4 +108,4 @@ For more detail on architecture, patterns, and platform notes, see the project
|
||||
|
||||
---
|
||||
|
||||
Thank you for contributing to AlphaHuman.
|
||||
Thank you for contributing to OpenHuman.
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
<h1 align="center">AlphaHuman</h1>
|
||||
<h1 align="center">OpenHuman</h1>
|
||||
|
||||
<p align="center">
|
||||
<strong>Your most productive co-worker</strong><br>
|
||||
A user-friendly (GUI-first) AI agent. AlphaHuman uses the
|
||||
<a href="https://github.com/tinyhumansai/neocortex/tree/main/mk1">Neocortex Mk1 model</a> to understand memories &
|
||||
realtime context at incredibly low costs.
|
||||
<strong>The age of super intelligence is here. OpenHuman is your artificially conscious human.</strong>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://discord.com/invite/k23Kn8nK">Discord</a> •
|
||||
<a href="https://www.reddit.com/r/tinyhumansai/">Reddit</a> •
|
||||
<a href="https://x.com/tinyhumansai">X/Twitter</a> •
|
||||
<a href="https://tinyhumans.gitbook.io/openhuman/">Docs</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/status-early%20beta-orange" alt="Early Beta" />
|
||||
<img src="https://img.shields.io/badge/platform-macOS%20%7C%20Windows%20%7C%20Linux%20%7C%20Android%20%7C%20iOS-blue" alt="Platforms" />
|
||||
<a href="https://github.com/alphahumanai/alphahuman/releases/latest"><img src="https://img.shields.io/github/v/release/alphahumanai/alphahuman?label=latest" alt="Latest Release" /></a>
|
||||
<img src="https://img.shields.io/badge/platform-desktop-macOS%20%7C%20Windows%20%7C%20Linux-blue" alt="Platforms: desktop only" />
|
||||
<a href="https://github.com/tinyhumansai/openhuman/releases/latest"><img src="https://img.shields.io/github/v/release/tinyhumansai/openhuman?label=latest" alt="Latest Release" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a target="_blank" href="https://discord.gg/k23Kn8nK"><img src="https://img.shields.io/badge/Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Discord" /></a>
|
||||
<a target="_blank" href="https://www.reddit.com/r/alphahuman"><img src="https://img.shields.io/badge/Reddit-FF4500?style=for-the-badge&logo=reddit&logoColor=white" alt="Reddit" /></a>
|
||||
<a target="_blank" href="https://x.com/alphahumanxyz"><img src="https://img.shields.io/badge/X-000000?style=for-the-badge&logo=x&logoColor=white" alt="Twitter/X" /></a>
|
||||
<img src="./docs/the-tet.jpg" alt="The Tet" />
|
||||
</p>
|
||||
|
||||

|
||||
|
||||
<p align="center" style="font-style: italic">
|
||||
"No Soul. No Humanity. The Tet. What a brilliant machine" — Morgan Freeman <a href="https://youtu.be/SveLVpqy_Rc?si=y83aZNokPiUjILN0&t=60">on alien superintelligence</a> in <em>Oblivion</em>
|
||||
"The Tet. What a brilliant machine" — Morgan Freeman as he recalls about <a href="https://youtu.be/SveLVpqy_Rc?si=y83aZNokPiUjILN0&t=60">alien superintelligence</a> in the movie <em>Oblivion</em>
|
||||
</p>
|
||||
|
||||
**Agentic system are everywhere.** Models wired into a script that call APIs, search, and file tools until the task looks done. That pattern is powerful for _tasks_, but it is not a self. It has no lasting inner model of _you_, no stable values across sessions, and no architecture for continuity at the scale of a life.
|
||||
|
||||
+5
-5
@@ -2,7 +2,7 @@
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We provide security updates for the following versions of AlphaHuman:
|
||||
We provide security updates for the following versions of OpenHuman:
|
||||
|
||||
| Version | Supported |
|
||||
| -------------- | ------------------ |
|
||||
@@ -10,7 +10,7 @@ We provide security updates for the following versions of AlphaHuman:
|
||||
| Previous minor | :white_check_mark: |
|
||||
| Older | :x: |
|
||||
|
||||
We recommend always running the [latest release](https://github.com/alphahumanxyz/alphahuman/releases/latest). AlphaHuman is in early beta; older versions may not receive patches.
|
||||
We recommend always running the [latest release](https://github.com/tinyhumansai/openhuman/releases/latest). OpenHuman is in early beta; older versions may not receive patches.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
@@ -19,7 +19,7 @@ We take security seriously. If you believe you have found a security vulnerabili
|
||||
### How to Report
|
||||
|
||||
1. **Do not** open a public GitHub issue for security vulnerabilities.
|
||||
2. Email the maintainers with a clear description of the issue, steps to reproduce, and impact. You can reach us via the contact details listed in the [AlphaHuman organization](https://github.com/alphahumanxyz) or repository.
|
||||
2. Email the maintainers with a clear description of the issue, steps to reproduce, and impact. You can reach us via the contact details listed in the [OpenHuman organization](https://github.com/openhumanxyz) or repository.
|
||||
3. Include as much detail as possible (platform, version, configuration) so we can reproduce and triage quickly.
|
||||
|
||||
### What to Expect
|
||||
@@ -38,7 +38,7 @@ We are especially interested in:
|
||||
- Issues in dependency chain (npm, Cargo) that affect our build or runtime
|
||||
- Platform-specific issues (macOS, Windows, Linux, Android, iOS) that compromise user data or device security
|
||||
|
||||
Out-of-scope for this process: general bugs, feature requests, and issues in third-party services we integrate with (e.g., Telegram, Notion) unless they are specific to how AlphaHuman uses them.
|
||||
Out-of-scope for this process: general bugs, feature requests, and issues in third-party services we integrate with (e.g., Telegram, Notion) unless they are specific to how OpenHuman uses them.
|
||||
|
||||
### Safe Harbor
|
||||
|
||||
@@ -50,4 +50,4 @@ We support safe harbor for security researchers who report in good faith. We wil
|
||||
- **Data**: Message content is processed on request and not retained for training or long-term storage.
|
||||
- **Skills**: Skills run in a sandboxed environment with defined boundaries; we review skill behavior and dependencies where possible.
|
||||
|
||||
Thank you for helping keep AlphaHuman and its users safe.
|
||||
Thank you for helping keep OpenHuman and its users safe.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# AlphaHuman Architecture
|
||||
# OpenHuman Architecture
|
||||
|
||||
**AI-powered super assistant for crypto communities, built on Rust.**
|
||||
|
||||
AlphaHuman is a cross-platform communication and automation platform purpose-built for the cryptocurrency ecosystem. A single React + Rust (Tauri) codebase can target multiple platforms; **what we document and ship for users today is desktop only** — **Windows, macOS, and Linux**. Android, iOS, and web are **not** supported in current docs or releases. The stack includes a sandboxed JavaScript skills engine, persistent Rust-native WebSocket infrastructure, and an AI tool protocol that lets language models invoke any connected service in real time.
|
||||
OpenHuman is a cross-platform communication and automation platform purpose-built for the cryptocurrency ecosystem. A single React + Rust (Tauri) codebase can target multiple platforms; **what we document and ship for users today is desktop only** — **Windows, macOS, and Linux**. Android, iOS, and web are **not** supported in current docs or releases. The stack includes a sandboxed JavaScript skills engine, persistent Rust-native WebSocket infrastructure, and an AI tool protocol that lets language models invoke any connected service in real time.
|
||||
|
||||
---
|
||||
|
||||
@@ -13,7 +13,7 @@ AlphaHuman is a cross-platform communication and automation platform purpose-bui
|
||||
**Not supported yet:** Android, iOS, standalone web client (may exist as experimental targets in the repo; do not treat as product-ready).
|
||||
|
||||
```
|
||||
AlphaHuman (shipping)
|
||||
OpenHuman (shipping)
|
||||
|
|
||||
Desktop
|
||||
/ | \
|
||||
@@ -65,9 +65,9 @@ The frontend communicates with the Rust core through Tauri's IPC bridge — 47+
|
||||
|
||||
## Rust-Powered Performance
|
||||
|
||||
AlphaHuman chose Tauri + Rust over Electron for fundamental performance and security reasons:
|
||||
OpenHuman chose Tauri + Rust over Electron for fundamental performance and security reasons:
|
||||
|
||||
| Metric | AlphaHuman (Tauri + Rust) | Typical Electron App |
|
||||
| Metric | OpenHuman (Tauri + Rust) | Typical Electron App |
|
||||
| ------------------------- | ------------------------------ | ---------------------------- |
|
||||
| Binary size | ~30 MB | ~150 MB+ |
|
||||
| Memory per skill context | ~1-2 MB (QuickJS) | ~150 MB+ (Chromium renderer) |
|
||||
@@ -76,7 +76,7 @@ AlphaHuman chose Tauri + Rust over Electron for fundamental performance and secu
|
||||
| Memory safety | Compile-time guaranteed | Runtime exceptions |
|
||||
| TLS implementation | rustls (no OpenSSL dependency) | Chromium's BoringSSL |
|
||||
|
||||
**Why this matters for a crypto platform**: Traders and analysts run AlphaHuman alongside resource-intensive tools — charting software, multiple browser tabs, trading terminals. A 30 MB footprint with sub-500ms startup means the app feels native and stays out of the way. Zero GC pauses means real-time price feeds and alerts are never delayed by memory management.
|
||||
**Why this matters for a crypto platform**: Traders and analysts run OpenHuman alongside resource-intensive tools — charting software, multiple browser tabs, trading terminals. A 30 MB footprint with sub-500ms startup means the app feels native and stays out of the way. Zero GC pauses means real-time price feeds and alerts are never delayed by memory management.
|
||||
|
||||
The **Tokio async runtime** drives all I/O — WebSocket connections, HTTP requests, file operations, and inter-skill communication — as non-blocking tasks on a thread pool. Thousands of concurrent operations (skill executions, cron jobs, socket events) share a small fixed set of OS threads.
|
||||
|
||||
@@ -84,7 +84,7 @@ The **Tokio async runtime** drives all I/O — WebSocket connections, HTTP reque
|
||||
|
||||
## Real-Time Socket Infrastructure
|
||||
|
||||
AlphaHuman implements a **dual-socket architecture**: a Rust-native WebSocket client on desktop and a JavaScript Socket.io client on web. The Rust implementation survives app backgrounding, operates independently of the WebView, and handles TLS via rustls.
|
||||
OpenHuman implements a **dual-socket architecture**: a Rust-native WebSocket client on desktop and a JavaScript Socket.io client on web. The Rust implementation survives app backgrounding, operates independently of the WebView, and handles TLS via rustls.
|
||||
|
||||
```
|
||||
Desktop Mode: Web Mode:
|
||||
@@ -119,7 +119,7 @@ The socket connection is **shared across all skills**. When events arrive, the s
|
||||
|
||||
## Skills Runtime Engine
|
||||
|
||||
AlphaHuman's defining capability is its **sandboxed JavaScript execution engine** running inside the Rust process. Skills are lightweight automation scripts that extend the platform with custom tools, integrations, and scheduled tasks.
|
||||
OpenHuman's defining capability is its **sandboxed JavaScript execution engine** running inside the Rust process. Skills are lightweight automation scripts that extend the platform with custom tools, integrations, and scheduled tasks.
|
||||
|
||||
```
|
||||
+---------------------------------------------------------------+
|
||||
@@ -188,7 +188,7 @@ Skills are synced from a GitHub repository and discovered at runtime. Platform f
|
||||
|
||||
## AI & Tool Protocol (MCP)
|
||||
|
||||
AlphaHuman implements the **Model Context Protocol** — a JSON-RPC 2.0 layer over Socket.io that lets AI models discover and invoke tools exposed by skills.
|
||||
OpenHuman implements the **Model Context Protocol** — a JSON-RPC 2.0 layer over Socket.io that lets AI models discover and invoke tools exposed by skills.
|
||||
|
||||
```
|
||||
User Prompt
|
||||
|
||||
@@ -15,3 +15,6 @@ todo
|
||||
[] - allow bundling of unverified skills
|
||||
[] - allow for new skills to be coded on their own
|
||||
[] - allow for multiple instances of a skill to be loaded
|
||||
[] - add a local model that can read through the screen and also go through voice using an API like whisper
|
||||
[] - add a screener recorder that goes through the intefaces in the screen and locally summarizes what is happening and brings more assitance to the user
|
||||
[] clean up the core so that we can run it as a binary on a server or as docker
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
# Rust SDK E2E Test Run — `example_e2e.rs`
|
||||
|
||||
**Run date:** 2026-03-27
|
||||
**Source:** `neocortex/packages/sdk-rust/tests/example_e2e.rs`
|
||||
**API base URL:** `https://staging-api.alphahuman.xyz`
|
||||
**Namespace:** `sdk-rust-e2e`
|
||||
**Document ID:** `sdk-rust-e2e-doc-single-1774605977640`
|
||||
|
||||
---
|
||||
|
||||
## What the test does
|
||||
|
||||
The file is a standalone end-to-end integration program (not a `#[test]`-annotated unit test). It exercises the `tinyhumansai` Rust SDK against the staging API in six sequential steps:
|
||||
|
||||
| Step | Operation | SDK method |
|
||||
| ---- | ------------------------------------ | ---------------------------------------------- |
|
||||
| 1 | Insert a memory document | `insert_memory` |
|
||||
| 2 | Poll ingestion job until complete | `get_ingestion_job` + `wait_for_ingestion_job` |
|
||||
| 3 | List documents filtered by namespace | `list_documents` |
|
||||
| 4 | Fetch the specific document | `get_document` |
|
||||
| 5 | Semantic query over the namespace | `query_memory` |
|
||||
| 6 | Recall all memory context | `recall_memory` |
|
||||
|
||||
The document inserted contains sprint velocity data for four teams (Atlas, Beacon, Comet, Delta).
|
||||
|
||||
---
|
||||
|
||||
## How to run
|
||||
|
||||
The file has its own `async fn main()` (annotated with `#[tokio::main]`), so Cargo's default test harness intercepts it and reports 0 tests. To run it as intended, add `harness = false` to `Cargo.toml` temporarily:
|
||||
|
||||
```toml
|
||||
[[test]]
|
||||
name = "example_e2e"
|
||||
harness = false
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```bash
|
||||
cd neocortex/packages/sdk-rust
|
||||
cargo test --test example_e2e
|
||||
```
|
||||
|
||||
> **Note:** `TINYHUMANS_TOKEN` in the file is intentionally left blank. Populate it with a valid API token before running.
|
||||
|
||||
---
|
||||
|
||||
## Step-by-step output
|
||||
|
||||
### Step 1 — `insertMemory`
|
||||
|
||||
**Endpoint:** `POST /memory/insert`
|
||||
|
||||
**Request body** (serialized from `InsertMemoryBody`; `priority`, `createdAt`, `updatedAt` omitted because they are `None` and marked `skip_serializing_if`):
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Sprint Dataset - Team Velocity",
|
||||
"content": "Sprint snapshot: Team Atlas completed 42 story points with 3 blockers, Team Beacon completed 35 story points with 1 blocker, Team Comet completed 48 story points with 5 blockers, and Team Delta completed 39 story points with 2 blockers. The highest velocity team is Team Comet and the fewest blockers team is Team Beacon.",
|
||||
"namespace": "sdk-rust-e2e",
|
||||
"sourceType": "doc",
|
||||
"metadata": { "source": "example_e2e.rs" },
|
||||
"documentId": "sdk-rust-e2e-doc-single-1774605977640"
|
||||
}
|
||||
```
|
||||
|
||||
**Result:** success
|
||||
**Job ID:** `a2a1396c-bcf5-4552-afc0-6c822bafd7c6`
|
||||
**Initial job state:** `pending`
|
||||
|
||||
```
|
||||
InsertMemoryResponse {
|
||||
success: true,
|
||||
data: InsertMemoryData {
|
||||
job_id: Some("a2a1396c-bcf5-4552-afc0-6c822bafd7c6"),
|
||||
state: Some("pending"),
|
||||
...
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 2 — `getIngestionJob` + `waitForIngestionJob`
|
||||
|
||||
**Endpoint:** `GET /memory/ingestion/jobs/{jobId}` (no request body)
|
||||
|
||||
**URL:** `GET /memory/ingestion/jobs/a2a1396c-bcf5-4552-afc0-6c822bafd7c6`
|
||||
|
||||
`wait_for_ingestion_job` then polls the same endpoint repeatedly (every 1 s, up to 30 s) until the state is not in `{pending, queued, processing, in_progress, started}`.
|
||||
|
||||
Initial poll returned state `processing`, so the SDK waited. Job completed successfully.
|
||||
|
||||
**Final state:** `completed`
|
||||
**Completed at:** `2026-03-27T10:06:24.974Z`
|
||||
**Ingestion latency:** `2.6173 s`
|
||||
|
||||
Key stats from the completed job response:
|
||||
|
||||
| Metric | Value |
|
||||
| --------------------- | ----------- |
|
||||
| Chunks new | 1 |
|
||||
| Chunks total | 1 |
|
||||
| Chunks deduplicated | 0 |
|
||||
| Entities extracted | 15 |
|
||||
| Relations extracted | 25 |
|
||||
| Sections | 1 |
|
||||
| Source type | `doc` |
|
||||
| Embedding tokens used | 244 |
|
||||
| Cost (USD) | $0.00000488 |
|
||||
|
||||
Timing breakdown (selected):
|
||||
|
||||
| Stage | Seconds |
|
||||
| -------------------- | -------- |
|
||||
| Chunking | 0.000826 |
|
||||
| Chunk embedding | 0.2688 |
|
||||
| Chunk storage | 0.2049 |
|
||||
| Entity extraction | 0.8131 |
|
||||
| Entity embedding | 0.0476 |
|
||||
| Graph structure | 0.2427 |
|
||||
| Relationship storage | 0.3800 |
|
||||
| Storage total | 1.2504 |
|
||||
|
||||
---
|
||||
|
||||
### Step 3 — `listDocuments`
|
||||
|
||||
**Endpoint:** `GET /memory/documents?namespace=sdk-rust-e2e&limit=10&offset=0` (no request body)
|
||||
|
||||
This run uses the updated `list_documents(ListDocumentsParams { namespace, limit, offset })` signature (new in the local SDK). Passing `namespace` now filters results correctly — previous runs returned an empty array because no namespace filter was applied.
|
||||
|
||||
**4 documents returned** (all previous E2E runs in this namespace):
|
||||
|
||||
| Document ID | Created at |
|
||||
| --------------------------------------- | ------------------------------ |
|
||||
| `sdk-rust-e2e-doc-single-1774598994566` | 2026-03-27T08:09:56 |
|
||||
| `sdk-rust-e2e-doc-single-1774600415507` | 2026-03-27T08:33:37 |
|
||||
| `sdk-rust-e2e-doc-single-1774604625874` | 2026-03-27T09:43:47 |
|
||||
| `sdk-rust-e2e-doc-single-1774605977640` | 2026-03-27T10:06:20 ← this run |
|
||||
|
||||
All share `namespace: "sdk-rust-e2e"`, `title: "Sprint Dataset - Team Velocity"`, `chunk_count: 1`.
|
||||
|
||||
---
|
||||
|
||||
### Step 4 — `getDocument`
|
||||
|
||||
**Endpoint:** `GET /memory/documents/{documentId}?namespace={namespace}` (no request body)
|
||||
|
||||
**URL:** `GET /memory/documents/sdk-rust-e2e-doc-single-1774605977640?namespace=sdk-rust-e2e`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"document_id": "sdk-rust-e2e-doc-single-1774605977640",
|
||||
"namespace": "sdk-rust-e2e",
|
||||
"title": "Sprint Dataset - Team Velocity",
|
||||
"chunk_count": 1,
|
||||
"chunk_ids": [-1427053832764092200],
|
||||
"created_at": "2026-03-27T10:06:20.655791+00:00",
|
||||
"updated_at": "2026-03-27T10:06:21.964953+00:00",
|
||||
"user_id": "69b12a6fd11460481185a040"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 5 — `queryMemory`
|
||||
|
||||
**Endpoint:** `POST /memory/query`
|
||||
|
||||
**Request body** (serialized from `QueryMemoryParams` with `#[serde(rename_all = "camelCase")]`; `documentIds` and `llmQuery` omitted because they are `None`):
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "Which team has the highest velocity and which team has the fewest blockers?",
|
||||
"includeReferences": true,
|
||||
"namespace": "sdk-rust-e2e",
|
||||
"maxChunks": 5.0
|
||||
}
|
||||
```
|
||||
|
||||
**Result:** 1 chunk returned with score `19.117`
|
||||
|
||||
The relevant chunk was retrieved correctly. The LLM context message assembled by the API:
|
||||
|
||||
```
|
||||
## Sources
|
||||
|
||||
[1] Section: Sprint Dataset - Team Velocity
|
||||
[1] Sprint snapshot: Team Atlas completed 42 story points with 3 blockers,
|
||||
Team Beacon completed 35 story points with 1 blocker, Team Comet
|
||||
completed 48 story points with 5 blockers, and Team Delta completed 39
|
||||
story points with 2 blockers. The highest velocity team is Team Comet
|
||||
and the fewest blockers team is Team Beacon.
|
||||
```
|
||||
|
||||
Top entity mentions extracted from the chunk (by normalized importance):
|
||||
|
||||
| Entity | Normalized importance | Count |
|
||||
| ------------------------- | --------------------- | ----- |
|
||||
| THE FEWEST BLOCKERS TEAM | 1.000 | 6 |
|
||||
| 42 STORY POINTS | 0.842 | 14 |
|
||||
| TEAM BEACON | 0.486 | 2 |
|
||||
| TEAM COMET | 0.476 | 2 |
|
||||
| THE HIGHEST VELOCITY TEAM | 0.440 | 4 |
|
||||
|
||||
**Usage:**
|
||||
|
||||
- Embedding tokens: 20
|
||||
- Cost: $0.0000004
|
||||
- Cached: false
|
||||
|
||||
---
|
||||
|
||||
### Step 6 — `recallMemoryContext`
|
||||
|
||||
**Endpoint:** `POST /memory/recall`
|
||||
|
||||
**Request body** (serialized from `RecallMemoryParams` with `#[serde(rename_all = "camelCase")]`):
|
||||
|
||||
```json
|
||||
{ "namespace": "sdk-rust-e2e", "maxChunks": 5.0 }
|
||||
```
|
||||
|
||||
Recall (no query — returns all recent/relevant context) returned the same chunk with a higher score of `31.357` (recall scoring differs from query scoring).
|
||||
|
||||
**Counts:** 1 chunk, 0 entities, 0 relations
|
||||
**Latency:** 2.8183 s
|
||||
**Usage:** 0 tokens, $0 cost (recall is embedding-free)
|
||||
**Cached:** false
|
||||
|
||||
The LLM context message was identical to step 5.
|
||||
|
||||
---
|
||||
|
||||
## Changes since previous run
|
||||
|
||||
| Area | Previous run | This run |
|
||||
| -------------------------------- | --------------------------------------- | ------------------------------------------------------------------ |
|
||||
| `step3_list_documents` signature | `list_documents()` — no args | `list_documents(ListDocumentsParams { namespace, limit, offset })` |
|
||||
| Step 3 result | Empty `documents: []` (no filter) | 4 documents returned (namespace filter working) |
|
||||
| Job ID | `4b3cc8e2-...` | `a2a1396c-...` |
|
||||
| Document ID | `sdk-rust-e2e-doc-single-1774600415507` | `sdk-rust-e2e-doc-single-1774605977640` |
|
||||
| Ingestion latency | 1.7791 s | 2.6173 s |
|
||||
| Entity extraction time | 0.0117 s | 0.8131 s |
|
||||
|
||||
---
|
||||
|
||||
## Overall result
|
||||
|
||||
```
|
||||
E2E Rust SDK example completed.
|
||||
```
|
||||
|
||||
All 6 steps passed. The SDK correctly:
|
||||
|
||||
- Inserted a document and received a job ID
|
||||
- Polled and waited for the ingestion job to reach `completed`
|
||||
- Listed documents filtered by namespace (returning all 4 prior E2E inserts)
|
||||
- Retrieved the document metadata by ID
|
||||
- Performed a semantic query and received the correct chunk with entity importance scores
|
||||
- Recalled memory context with latency and count metadata
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The Tauri Rust backend provides native functionality for the AlphaHuman desktop application:
|
||||
The Tauri Rust backend provides native functionality for the OpenHuman desktop application:
|
||||
|
||||
- System tray with background execution
|
||||
- Deep link authentication
|
||||
@@ -113,7 +113,7 @@ listen("socket:should_connect", (event) => {
|
||||
| Plugin | Version | Purpose |
|
||||
| --------------------------- | ------- | --------------------------- |
|
||||
| `tauri-plugin-opener` | 2 | Open URLs in browser |
|
||||
| `tauri-plugin-deep-link` | 2.0.0 | Handle `alphahuman://` URLs |
|
||||
| `tauri-plugin-deep-link` | 2.0.0 | Handle `openhuman://` URLs |
|
||||
| `tauri-plugin-autostart` | 2 | Launch at login |
|
||||
| `tauri-plugin-notification` | 2 | Native notifications |
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ Open Telegram login widget in browser.
|
||||
|
||||
```typescript
|
||||
await invoke("start_telegram_login");
|
||||
// Opens ${DEFAULT_BACKEND_URL}/auth/telegram-widget?redirect=alphahuman://auth
|
||||
// Opens ${DEFAULT_BACKEND_URL}/auth/telegram-widget?redirect=openhuman://auth
|
||||
```
|
||||
|
||||
### `start_telegram_login_with_url`
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
This documentation covers the Tauri Rust backend for the AlphaHuman desktop application.
|
||||
This documentation covers the Tauri Rust backend for the OpenHuman desktop application.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
@@ -26,7 +26,7 @@ This documentation covers the Tauri Rust backend for the AlphaHuman desktop appl
|
||||
### Existing Implementation (`lib.rs`)
|
||||
|
||||
- ✅ System tray with show/hide/quit
|
||||
- ✅ Deep link handling (`alphahuman://` scheme)
|
||||
- ✅ Deep link handling (`openhuman://` scheme)
|
||||
- ✅ Token exchange command (CORS bypass)
|
||||
- ✅ Autostart plugin (macOS LaunchAgent)
|
||||
- ✅ Window minimize-to-tray on close (macOS)
|
||||
@@ -120,7 +120,7 @@ impl SocketService {
|
||||
1. User clicks "Login with Telegram" in desktop app
|
||||
↓
|
||||
2. App opens system browser to:
|
||||
${BACKEND_URL}/auth/telegram-widget?redirect=alphahuman://auth
|
||||
${BACKEND_URL}/auth/telegram-widget?redirect=openhuman://auth
|
||||
↓
|
||||
3. Backend serves Telegram Login Widget HTML page
|
||||
↓
|
||||
@@ -128,7 +128,7 @@ impl SocketService {
|
||||
↓
|
||||
5. Telegram callback → Backend validates → Creates loginToken
|
||||
↓
|
||||
6. Backend redirects to: alphahuman://auth?token={loginToken}
|
||||
6. Backend redirects to: openhuman://auth?token={loginToken}
|
||||
↓
|
||||
7. Desktop app catches deep link
|
||||
↓
|
||||
@@ -153,7 +153,7 @@ Returns HTML page with Telegram Login Widget that redirects to the specified sch
|
||||
#[tauri::command]
|
||||
async fn start_telegram_login(app: AppHandle) -> Result<(), String> {
|
||||
// Open browser to Telegram widget page
|
||||
let url = format!("{}/auth/telegram-widget?redirect=alphahuman://auth", BACKEND_URL);
|
||||
let url = format!("{}/auth/telegram-widget?redirect=openhuman://auth", BACKEND_URL);
|
||||
opener::open(&url)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -189,7 +189,7 @@ pub struct SessionService {
|
||||
}
|
||||
|
||||
impl SessionService {
|
||||
const SERVICE: &'static str = "com.alphahuman.app";
|
||||
const SERVICE: &'static str = "com.openhuman.app";
|
||||
|
||||
pub fn store_token(&self, token: &str) -> Result<(), Error>;
|
||||
pub fn get_token(&self) -> Result<Option<String>, Error>;
|
||||
|
||||
@@ -105,7 +105,7 @@ MCP System:
|
||||
### Authentication Flow (Deep Link)
|
||||
|
||||
1. User authenticates in browser → receives `loginToken`
|
||||
2. Browser redirects to `alphahuman://auth?token=<loginToken>`
|
||||
2. Browser redirects to `openhuman://auth?token=<loginToken>`
|
||||
3. Desktop app catches deep link via Tauri plugin
|
||||
4. `desktopDeepLinkListener` invokes Rust `exchange_token` command
|
||||
5. Rust calls backend `POST /auth/desktop-exchange` (CORS-free)
|
||||
|
||||
@@ -366,7 +366,7 @@ import('./utils/desktopDeepLinkListener').then(m => {
|
||||
});
|
||||
```
|
||||
|
||||
The listener intercepts `alphahuman://auth?token=...` and:
|
||||
The listener intercepts `openhuman://auth?token=...` and:
|
||||
|
||||
1. Exchanges token via Rust command
|
||||
2. Stores session in Redux
|
||||
|
||||
@@ -173,12 +173,6 @@ Environment variable access with defaults.
|
||||
// Backend URL
|
||||
export const BACKEND_URL = import.meta.env.VITE_BACKEND_URL || 'https://api.example.com';
|
||||
|
||||
// Telegram configuration
|
||||
export const TELEGRAM_API_ID = import.meta.env.VITE_TELEGRAM_API_ID;
|
||||
export const TELEGRAM_API_HASH = import.meta.env.VITE_TELEGRAM_API_HASH;
|
||||
export const TELEGRAM_BOT_USERNAME = import.meta.env.VITE_TELEGRAM_BOT_USERNAME;
|
||||
export const TELEGRAM_BOT_ID = import.meta.env.VITE_TELEGRAM_BOT_ID;
|
||||
|
||||
// Debug mode
|
||||
export const DEBUG = import.meta.env.VITE_DEBUG === 'true';
|
||||
```
|
||||
@@ -214,7 +208,7 @@ import { buildAuthDeepLink } from '../utils/deeplink';
|
||||
|
||||
// Build URL for browser redirect
|
||||
const deepLink = buildAuthDeepLink(loginToken);
|
||||
// → "alphahuman://auth?token=abc123"
|
||||
// → "openhuman://auth?token=abc123"
|
||||
|
||||
// In web frontend after auth:
|
||||
window.location.href = deepLink;
|
||||
@@ -241,7 +235,7 @@ import('./utils/desktopDeepLinkListener').then(m => {
|
||||
**What it does:**
|
||||
|
||||
1. Listens for `onOpenUrl` events from Tauri deep-link plugin
|
||||
2. Parses `alphahuman://auth?token=...` URLs
|
||||
2. Parses `openhuman://auth?token=...` URLs
|
||||
3. Calls Rust `exchange_token` command (bypasses CORS)
|
||||
4. Stores session in Redux
|
||||
5. Navigates to `/onboarding` or `/home`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Telegram Login (Web → Desktop Handoff)
|
||||
|
||||
This app implements **Telegram login for the desktop (Tauri) client** using a **system-browser auth flow** plus a **custom URL scheme deep link** (`alphahuman://`) to return control back to the desktop app.
|
||||
This app implements **Telegram login for the desktop (Tauri) client** using a **system-browser auth flow** plus a **custom URL scheme deep link** (`openhuman://`) to return control back to the desktop app.
|
||||
|
||||
---
|
||||
|
||||
@@ -8,10 +8,10 @@ This app implements **Telegram login for the desktop (Tauri) client** using a **
|
||||
|
||||
1. **User clicks “Continue with Telegram”** inside the desktop app.
|
||||
2. The app opens the system browser to the backend:
|
||||
- `GET ${BACKEND_URL}/auth/telegram-widget?redirect=alphahuman://auth`
|
||||
- `GET ${BACKEND_URL}/auth/telegram-widget?redirect=openhuman://auth`
|
||||
3. The backend performs Telegram authentication (bot-based login / OAuth-like flow).
|
||||
4. On success, the backend generates a **short-lived single-use `loginToken`** and redirects the browser to:
|
||||
- `alphahuman://auth?token=<loginToken>`
|
||||
- `openhuman://auth?token=<loginToken>`
|
||||
5. The OS routes that deep link to the installed desktop app.
|
||||
6. The desktop app extracts the `token` from the deep link and exchanges it for a **long-lived `sessionToken`** by calling a Rust Tauri command (bypassing CORS):
|
||||
- `POST ${BACKEND_URL}/auth/desktop-exchange` with `{ token }`
|
||||
@@ -41,7 +41,7 @@ export const BACKEND_URL =
|
||||
The URL scheme is declared in `src-tauri/tauri.conf.json`:
|
||||
|
||||
```json
|
||||
{ "plugins": { "deep-link": { "desktop": { "schemes": ["alphahuman"] } } } }
|
||||
{ "plugins": { "deep-link": { "desktop": { "schemes": ["openhuman"] } } } }
|
||||
```
|
||||
|
||||
The deep-link plugin is initialized in `src-tauri/src/lib.rs`:
|
||||
@@ -78,8 +78,8 @@ import('./utils/desktopDeepLinkListener').then(m => {
|
||||
|
||||
The deep link handler:
|
||||
|
||||
- Accepts only the `alphahuman:` scheme
|
||||
- Requires `alphahuman://auth?token=...`
|
||||
- Accepts only the `openhuman:` scheme
|
||||
- Requires `openhuman://auth?token=...`
|
||||
- Calls the Rust command `exchange_token`
|
||||
- Stores `sessionToken` in Redux auth state
|
||||
- Redirects to `#/onboarding` (HashRouter)
|
||||
@@ -92,7 +92,7 @@ const handleDeepLinkUrls = async (urls: string[] | null | undefined) => {
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
<<<<<<< HEAD
|
||||
if (parsed.protocol !== 'alphahuman:') return;
|
||||
if (parsed.protocol !== 'openhuman:') return;
|
||||
if (parsed.hostname !== 'auth') return;
|
||||
=======
|
||||
if (parsed.protocol !== "outsourced:") return;
|
||||
@@ -141,13 +141,13 @@ async fn exchange_token(backend_url: String, token: String) -> Result<serde_json
|
||||
|
||||
Your backend must implement **both**:
|
||||
|
||||
### A) `GET /auth/telegram-widget?redirect=alphahuman://auth`
|
||||
### A) `GET /auth/telegram-widget?redirect=openhuman://auth`
|
||||
|
||||
- **Purpose**: start Telegram auth in the user’s browser.
|
||||
- **On success**:
|
||||
- create/find user
|
||||
- mint a **short-lived** `loginToken` (single-use, recommended TTL \(\le 5\) minutes)
|
||||
- redirect to: `alphahuman://auth?token=<loginToken>`
|
||||
- redirect to: `openhuman://auth?token=<loginToken>`
|
||||
|
||||
### B) `POST /auth/desktop-exchange`
|
||||
|
||||
@@ -180,7 +180,7 @@ Your backend must implement **both**:
|
||||
|
||||
### Backend (required)
|
||||
|
||||
- **Implement `GET /auth/telegram?platform=desktop`** and ensure it redirects to `alphahuman://auth?token=...` on success.
|
||||
- **Implement `GET /auth/telegram?platform=desktop`** and ensure it redirects to `openhuman://auth?token=...` on success.
|
||||
- **Implement `POST /auth/desktop-exchange`** to exchange the login token for a session token.
|
||||
- **Enforce security**:
|
||||
- `loginToken` is **single-use**
|
||||
@@ -190,7 +190,7 @@ Your backend must implement **both**:
|
||||
### Desktop app (required for reliable behavior)
|
||||
|
||||
- **Ensure the deep-link plugin is configured and permitted**:
|
||||
- `src-tauri/tauri.conf.json` includes `"schemes": ["alphahuman"]`
|
||||
- `src-tauri/tauri.conf.json` includes `"schemes": ["openhuman"]`
|
||||
- `src-tauri/capabilities/default.json` includes `"deep-link:default"`
|
||||
- **Use a real backend URL**:
|
||||
- set `VITE_BACKEND_URL` for dev/prod so `Login.tsx` opens the correct domain
|
||||
@@ -198,7 +198,7 @@ Your backend must implement **both**:
|
||||
### Desktop app (recommended hardening / cleanup)
|
||||
|
||||
- **Validate the deep link target more strictly** in `src/utils/desktopDeepLinkListener.ts`:
|
||||
- today it checks only `parsed.protocol === 'alphahuman:'`
|
||||
- today it checks only `parsed.protocol === 'openhuman:'`
|
||||
- recommended: also require `parsed.hostname === 'auth'` (and optionally a known path)
|
||||
- **Don’t skip Telegram auth in onboarding**:
|
||||
- `src/pages/onboarding/Step1Phone.tsx` currently has a “Continue with Telegram” button that _only navigates_ and does not authenticate.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,549 @@
|
||||
# TinyHumans AI SDK — Reference & Project Integration
|
||||
|
||||
**Crate:** [`tinyhumansai`](https://crates.io/crates/tinyhumansai)
|
||||
**Version:** 0.1.6
|
||||
**License:** MIT
|
||||
**Repository:** https://github.com/tinyhumansai/neocortex/tree/main/packages/sdk-rust
|
||||
|
||||
The `tinyhumansai` Rust SDK is a typed async client for the TinyHumans Neocortex memory API. It supports inserting, querying, recalling, and deleting memory — plus ingestion job tracking, document management, and skill-data sync.
|
||||
|
||||
---
|
||||
|
||||
## Client Setup
|
||||
|
||||
### `TinyHumanConfig`
|
||||
|
||||
```rust
|
||||
let config = TinyHumanConfig::new("your-api-token");
|
||||
|
||||
// Override the base URL (optional)
|
||||
let config = config.with_base_url("https://staging-api.alphahuman.xyz");
|
||||
```
|
||||
|
||||
Base URL resolution order:
|
||||
|
||||
1. `with_base_url(...)` call
|
||||
2. `TINYHUMANS_BASE_URL` env var
|
||||
3. `NEOCORTEX_BASE_URL` env var
|
||||
4. Default: `https://api.tinyhumans.ai`
|
||||
|
||||
### `TinyHumansMemoryClient::new`
|
||||
|
||||
```rust
|
||||
let client = TinyHumansMemoryClient::new(config)?;
|
||||
```
|
||||
|
||||
Validates that the token is non-empty. Returns `TinyHumansError::Validation` if it is.
|
||||
Sets a 30-second HTTP timeout on all requests. Uses `rustls` for TLS.
|
||||
|
||||
---
|
||||
|
||||
## SDK Functions
|
||||
|
||||
### `insert_memory`
|
||||
|
||||
**Endpoint:** `POST /memory/insert`
|
||||
|
||||
Ingests a document into the memory store. Returns a job ID — ingestion is asynchronous.
|
||||
|
||||
```rust
|
||||
let res = client.insert_memory(InsertMemoryParams {
|
||||
title: "Sprint Dataset - Team Velocity".to_string(),
|
||||
content: "...".to_string(),
|
||||
namespace: "sdk-rust-e2e".to_string(),
|
||||
document_id: "my-doc-id".to_string(),
|
||||
metadata: Some(serde_json::json!({ "source": "example.rs" })),
|
||||
..Default::default()
|
||||
}).await?;
|
||||
|
||||
let job_id = res.data.job_id; // Option<String>
|
||||
```
|
||||
|
||||
**`InsertMemoryParams`**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ------------- | --------------------------- | -------- | ----------------------------------- |
|
||||
| `title` | `String` | Yes | Document title |
|
||||
| `content` | `String` | Yes | Document text content |
|
||||
| `namespace` | `String` | Yes | Logical partition for the document |
|
||||
| `document_id` | `String` | Yes | Caller-supplied unique ID |
|
||||
| `source_type` | `Option<SourceType>` | No | `Doc` (default), `Chat`, or `Email` |
|
||||
| `metadata` | `Option<serde_json::Value>` | No | Arbitrary JSON metadata |
|
||||
| `priority` | `Option<Priority>` | No | `High`, `Medium`, or `Low` |
|
||||
| `created_at` | `Option<f64>` | No | Unix timestamp (ms) |
|
||||
| `updated_at` | `Option<f64>` | No | Unix timestamp (ms) |
|
||||
|
||||
**Serialised request body** (fields with `None` values are omitted):
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "...",
|
||||
"content": "...",
|
||||
"namespace": "...",
|
||||
"sourceType": "doc",
|
||||
"metadata": { "source": "example.rs" },
|
||||
"documentId": "my-doc-id"
|
||||
}
|
||||
```
|
||||
|
||||
**`InsertMemoryResponse`**
|
||||
|
||||
```rust
|
||||
InsertMemoryResponse {
|
||||
success: true,
|
||||
data: InsertMemoryData {
|
||||
job_id: Some("a2a1396c-..."),
|
||||
state: Some("pending"),
|
||||
status: None,
|
||||
stats: None,
|
||||
usage: None,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `get_ingestion_job`
|
||||
|
||||
**Endpoint:** `GET /memory/ingestion/jobs/{jobId}`
|
||||
|
||||
Fetches the current status of an ingestion job.
|
||||
|
||||
```rust
|
||||
let res = client.get_ingestion_job("a2a1396c-bcf5-4552-afc0-6c822bafd7c6").await?;
|
||||
println!("{:?}", res.data.state); // Some("processing") | Some("completed") | ...
|
||||
```
|
||||
|
||||
**`IngestionJobStatusResponse`**
|
||||
|
||||
| Field | Type | Description |
|
||||
| -------------- | --------------------------- | ----------------------------------------------------------- |
|
||||
| `job_id` | `Option<String>` | The job ID |
|
||||
| `state` | `Option<String>` | `pending`, `processing`, `completed`, `failed`, etc. |
|
||||
| `endpoint` | `Option<String>` | API endpoint that created the job |
|
||||
| `attempts` | `Option<f64>` | Number of execution attempts |
|
||||
| `error` | `Option<String>` | Error message if failed |
|
||||
| `response` | `Option<serde_json::Value>` | Full ingestion result (stats, timings, usage) on completion |
|
||||
| `created_at` | `Option<String>` | ISO 8601 timestamp |
|
||||
| `started_at` | `Option<String>` | ISO 8601 timestamp |
|
||||
| `completed_at` | `Option<String>` | ISO 8601 timestamp |
|
||||
|
||||
Completed response includes ingestion stats (chunk count, entity count, relation count, timings, embedding token usage, and cost in USD).
|
||||
|
||||
---
|
||||
|
||||
### `wait_for_ingestion_job`
|
||||
|
||||
Polls `get_ingestion_job` until the job reaches a terminal state.
|
||||
|
||||
```rust
|
||||
let res = client.wait_for_ingestion_job(
|
||||
"a2a1396c-...",
|
||||
Some(30_000), // timeout_ms
|
||||
Some(1_000), // poll_interval_ms
|
||||
).await?;
|
||||
```
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
| ------------------ | ------------- | ------- | ------------------------ |
|
||||
| `job_id` | `&str` | — | Job to poll |
|
||||
| `timeout_ms` | `Option<u64>` | 30 000 | Max wait in milliseconds |
|
||||
| `poll_interval_ms` | `Option<u64>` | 1 000 | Polling interval |
|
||||
|
||||
**Terminal states:** `completed`, `done`, `succeeded`, `success` → returns `Ok`.
|
||||
**Failure states:** `failed`, `error`, `cancelled` → returns `Err`.
|
||||
**Timeout:** returns `TinyHumansError::Api { status: 408 }`.
|
||||
|
||||
---
|
||||
|
||||
### `query_memory`
|
||||
|
||||
**Endpoint:** `POST /memory/query`
|
||||
|
||||
Semantic (RAG) query over stored memory. Returns ranked chunks relevant to the query.
|
||||
|
||||
```rust
|
||||
let res = client.query_memory(QueryMemoryParams {
|
||||
query: "Which team has the highest velocity?".to_string(),
|
||||
namespace: Some("sdk-rust-e2e".to_string()),
|
||||
include_references: Some(true),
|
||||
max_chunks: Some(5.0),
|
||||
..Default::default()
|
||||
}).await?;
|
||||
```
|
||||
|
||||
**`QueryMemoryParams`** (`#[serde(rename_all = "camelCase")]`)
|
||||
|
||||
| Field | Type | Serialised as | Description |
|
||||
| -------------------- | --------------------- | --------------------- | ----------------------------- |
|
||||
| `query` | `String` | `"query"` | The search query |
|
||||
| `namespace` | `Option<String>` | `"namespace"` | Filter by namespace |
|
||||
| `include_references` | `Option<bool>` | `"includeReferences"` | Include source chunk metadata |
|
||||
| `max_chunks` | `Option<f64>` | `"maxChunks"` | Max chunks to retrieve |
|
||||
| `document_ids` | `Option<Vec<String>>` | `"documentIds"` | Filter to specific documents |
|
||||
| `llm_query` | `Option<String>` | `"llmQuery"` | Override query sent to LLM |
|
||||
|
||||
**`QueryMemoryResponse`**
|
||||
|
||||
```rust
|
||||
QueryMemoryResponse {
|
||||
success: true,
|
||||
data: QueryMemoryData {
|
||||
context: Some(QueryContextOut {
|
||||
entities: [],
|
||||
relations: [],
|
||||
chunks: [ /* matched chunks with scores and entity_mentions */ ],
|
||||
}),
|
||||
usage: Some(Usage {
|
||||
embedding_tokens: 20,
|
||||
cost_usd: 0.0000004,
|
||||
llm_input_tokens: 0,
|
||||
llm_output_tokens: 0,
|
||||
}),
|
||||
cached: false,
|
||||
llm_context_message: Some("## Sources\n\n[1] ..."),
|
||||
response: None, // populated if LLM response was requested
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`llm_context_message` is a pre-formatted string ready for injection into an LLM prompt.
|
||||
|
||||
---
|
||||
|
||||
### `recall_memory`
|
||||
|
||||
**Endpoint:** `POST /memory/recall`
|
||||
|
||||
Recalls synthesised context from the Master memory node for a namespace — no query required. Returns the most relevant accumulated context.
|
||||
|
||||
```rust
|
||||
let res = client.recall_memory(RecallMemoryParams {
|
||||
namespace: Some("sdk-rust-e2e".to_string()),
|
||||
max_chunks: Some(5.0),
|
||||
}).await?;
|
||||
```
|
||||
|
||||
**`RecallMemoryParams`** (`#[serde(rename_all = "camelCase")]`)
|
||||
|
||||
| Field | Type | Serialised as | Description |
|
||||
| ------------ | ---------------- | ------------- | ------------------------ |
|
||||
| `namespace` | `Option<String>` | `"namespace"` | Namespace to recall from |
|
||||
| `max_chunks` | `Option<f64>` | `"maxChunks"` | Max chunks to return |
|
||||
|
||||
**`RecallMemoryResponse`**
|
||||
|
||||
```rust
|
||||
RecallMemoryResponse {
|
||||
success: true,
|
||||
data: RecallMemoryData {
|
||||
context: Some(/* raw JSON object with chunks, entities, relations */),
|
||||
llm_context_message: Some("## Sources\n\n[1] ..."),
|
||||
response: None,
|
||||
cached: false,
|
||||
latency_seconds: Some(2.8183),
|
||||
counts: Some(RecallCounts {
|
||||
num_chunks: 1,
|
||||
num_entities: 0,
|
||||
num_relations: 0,
|
||||
}),
|
||||
usage: Some(/* cost/token breakdown */),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Recall is embedding-free (0 tokens, $0 cost) unlike `query_memory`.
|
||||
|
||||
---
|
||||
|
||||
### `delete_memory`
|
||||
|
||||
**Endpoint:** `POST /memory/admin/delete`
|
||||
|
||||
Deletes all memory for a namespace (or all memory if namespace is omitted).
|
||||
|
||||
```rust
|
||||
client.delete_memory(DeleteMemoryParams {
|
||||
namespace: Some("skill:gmail:user@example.com".to_string()),
|
||||
}).await?;
|
||||
```
|
||||
|
||||
**`DeleteMemoryResponse`**
|
||||
|
||||
```rust
|
||||
DeleteMemoryData {
|
||||
status: "ok",
|
||||
user_id: "...",
|
||||
namespace: Some("skill:gmail:user@example.com"),
|
||||
nodes_deleted: 42,
|
||||
message: "...",
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `list_documents`
|
||||
|
||||
**Endpoint:** `GET /memory/documents?namespace=...&limit=...&offset=...`
|
||||
|
||||
Lists ingested documents with optional namespace filtering and pagination.
|
||||
|
||||
```rust
|
||||
let res = client.list_documents(ListDocumentsParams {
|
||||
namespace: Some("sdk-rust-e2e".to_string()),
|
||||
limit: Some(10.0),
|
||||
offset: Some(0.0),
|
||||
}).await?;
|
||||
```
|
||||
|
||||
**`ListDocumentsParams`**
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----------- | ---------------- | --------------------- |
|
||||
| `namespace` | `Option<String>` | Filter by namespace |
|
||||
| `limit` | `Option<f64>` | Max results to return |
|
||||
| `offset` | `Option<f64>` | Pagination offset |
|
||||
|
||||
Returns `serde_json::Value` with a `data.documents` array. Each document includes `document_id`, `namespace`, `title`, `chunk_count`, `created_at`, `updated_at`, `user_id`.
|
||||
|
||||
---
|
||||
|
||||
### `get_document`
|
||||
|
||||
**Endpoint:** `GET /memory/documents/{documentId}?namespace={namespace}`
|
||||
|
||||
Fetches metadata for a single document by ID.
|
||||
|
||||
```rust
|
||||
let res = client.get_document("my-doc-id", Some("my-namespace")).await?;
|
||||
```
|
||||
|
||||
Returns `serde_json::Value` with `document_id`, `namespace`, `title`, `chunk_count`, `chunk_ids`, timestamps, and `user_id`.
|
||||
|
||||
---
|
||||
|
||||
### `delete_document`
|
||||
|
||||
**Endpoint:** `DELETE /memory/documents/{documentId}?namespace={namespace}`
|
||||
|
||||
Deletes a specific document from a namespace.
|
||||
|
||||
```rust
|
||||
client.delete_document("my-doc-id", "my-namespace").await?;
|
||||
```
|
||||
|
||||
Both `document_id` and `namespace` are required (validated before the request is sent).
|
||||
|
||||
---
|
||||
|
||||
### Other SDK Methods (Available, Not Used in Project)
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
| ------------------------- | ---------------------------------- | ----------------------------- |
|
||||
| `insert_document` | `POST /memory/documents` | Insert via documents route |
|
||||
| `insert_documents_batch` | `POST /memory/documents/batch` | Batch insert documents |
|
||||
| `recall_memories` | `POST /memory/memories/recall` | Recall from Ebbinghaus bank |
|
||||
| `recall_memories_context` | `POST /memory/memories/context` | Recall context from memories |
|
||||
| `recall_thoughts` | `POST /memory/memories/thoughts` | Reflective thought generation |
|
||||
| `interact_memory` | `POST /memory/interact` | Record entity interactions |
|
||||
| `record_interactions` | `POST /memory/interactions` | Record interaction signals |
|
||||
| `query_memory_context` | `POST /memory/queries` | Query alias route |
|
||||
| `chat_memory_context` | `POST /memory/conversations` | Chat with memory context |
|
||||
| `chat_memory` | `POST /memory/chat` | Chat via DeltaNet cache |
|
||||
| `sync_memory` | `POST /memory/sync` | Sync OpenClaw workspace files |
|
||||
| `memory_health` | `GET /memory/health` | Health check |
|
||||
| `get_graph_snapshot` | `GET /memory/admin/graph-snapshot` | Admin graph data |
|
||||
|
||||
---
|
||||
|
||||
## Error Types
|
||||
|
||||
**`TinyHumansError`**
|
||||
|
||||
| Variant | When |
|
||||
| ------------------------------- | -------------------------------------------------------------- |
|
||||
| `Validation(String)` | Client-side validation failed (empty token, empty title, etc.) |
|
||||
| `Http(String)` | Network/transport error from `reqwest` |
|
||||
| `Api { message, status, body }` | Non-2xx response from the API |
|
||||
| `Decode(String)` | Failed to deserialise response JSON |
|
||||
|
||||
---
|
||||
|
||||
## Project Integration (`openhuman`)
|
||||
|
||||
### How the SDK is Initialised
|
||||
|
||||
**File:** `src-tauri/src/memory/mod.rs`
|
||||
|
||||
The project wraps `TinyHumansMemoryClient` in a `MemoryClient` struct. Construction happens at runtime via the `init_memory_client` Tauri command, using the user's JWT from Redux `authSlice.token` — not a hardcoded API key.
|
||||
|
||||
```rust
|
||||
pub fn from_token(jwt_token: String) -> Option<Self> {
|
||||
// Base URL resolved in order:
|
||||
// 1. OPENHUMAN_BASE_URL env var
|
||||
// 2. TINYHUMANS_BASE_URL env var
|
||||
// 3. get_backend_url() — app's configured backend
|
||||
let config = TinyHumanConfig::new(jwt_token).with_base_url(resolved_url);
|
||||
TinyHumansMemoryClient::new(config).ok().map(|inner| Self { inner })
|
||||
}
|
||||
```
|
||||
|
||||
The client is stored as `Arc<MemoryClient>` inside a `Mutex<Option<MemoryClientRef>>` (`MemoryState`), shared across Tauri commands.
|
||||
|
||||
---
|
||||
|
||||
### `MemoryClient` Wrapper Methods
|
||||
|
||||
The `MemoryClient` wrapper exposes higher-level methods used throughout the app:
|
||||
|
||||
#### `store_skill_sync`
|
||||
|
||||
Calls `insert_memory` then polls `ingestion_job_status` every **30 seconds** until the job is `completed` or `failed`. Used after skill OAuth completion and periodic skill syncs.
|
||||
|
||||
```rust
|
||||
client.store_skill_sync(
|
||||
skill_id, // becomes the namespace
|
||||
integration_id, // e.g. "user@example.com"
|
||||
title,
|
||||
content,
|
||||
source_type, // Option<SourceType>
|
||||
metadata, // Option<serde_json::Value>
|
||||
priority, // Option<Priority>
|
||||
created_at, // Option<f64>
|
||||
updated_at, // Option<f64>
|
||||
document_id, // Option<String> — auto-generated UUID if None
|
||||
).await?;
|
||||
```
|
||||
|
||||
> Note: polling interval is 30 s (fire-and-forget background task). The E2E test uses `wait_for_ingestion_job` with 1 s polling instead.
|
||||
|
||||
#### `query_skill_context`
|
||||
|
||||
Calls `query_memory` for a skill's namespace. Returns the `response` string from the API (LLM-synthesised answer).
|
||||
|
||||
```rust
|
||||
let context: String = client.query_skill_context(
|
||||
skill_id, // namespace
|
||||
integration_id, // unused currently
|
||||
"What emails were recently synced?",
|
||||
10, // max_chunks
|
||||
).await?;
|
||||
```
|
||||
|
||||
#### `recall_skill_context`
|
||||
|
||||
Calls `recall_memory` for a namespace. Returns `Option<serde_json::Value>` (the raw `context` field).
|
||||
|
||||
```rust
|
||||
let ctx: Option<serde_json::Value> = client.recall_skill_context(
|
||||
skill_id,
|
||||
integration_id,
|
||||
10, // max_chunks
|
||||
).await?;
|
||||
```
|
||||
|
||||
#### `clear_skill_memory`
|
||||
|
||||
Calls `delete_memory` with `namespace = skill_id`. Used on OAuth revoke / skill disconnect.
|
||||
|
||||
```rust
|
||||
client.clear_skill_memory("gmail", "user@example.com").await?;
|
||||
// → DELETE namespace "gmail"
|
||||
```
|
||||
|
||||
#### `query_namespace_context` / `recall_namespace_context`
|
||||
|
||||
Direct namespace versions of query/recall — bypass the `skill:{id}:{id}` namespace convention.
|
||||
|
||||
#### `list_documents` / `delete_document`
|
||||
|
||||
Thin pass-through wrappers over the SDK methods.
|
||||
|
||||
---
|
||||
|
||||
### Memory in the Chat Agentic Loop
|
||||
|
||||
**File:** `src-tauri/src/commands/chat.rs`
|
||||
|
||||
Every `chat_send` call (desktop) performs these memory operations before hitting the inference API:
|
||||
|
||||
**Step 2 — Conversation recall**
|
||||
|
||||
```rust
|
||||
mem.recall_skill_context("conversations", thread_id, 10).await
|
||||
```
|
||||
|
||||
Recalls context from the `conversations` namespace, keyed by `thread_id`. The result is injected into the user message as:
|
||||
|
||||
```
|
||||
[MEMORY_CONTEXT]
|
||||
{recalled context}
|
||||
[/MEMORY_CONTEXT]
|
||||
|
||||
{user message}
|
||||
```
|
||||
|
||||
**Step 2b — Skill context recall**
|
||||
|
||||
For every skill with registered tools, recalls its memory:
|
||||
|
||||
```rust
|
||||
mem.recall_skill_context(skill_id, skill_id, 10).await
|
||||
```
|
||||
|
||||
Each result is injected as:
|
||||
|
||||
```
|
||||
[{SKILL_ID}_CONTEXT]
|
||||
{recalled context}
|
||||
[/{SKILL_ID}_CONTEXT]
|
||||
```
|
||||
|
||||
The full assembled user message sent to the inference API looks like:
|
||||
|
||||
```
|
||||
## Project Context
|
||||
{openclaw_context — SOUL.md, IDENTITY.md, TOOLS.md, etc.}
|
||||
|
||||
User message: {original message}
|
||||
|
||||
[MEMORY_CONTEXT]
|
||||
{conversation memory}
|
||||
[/MEMORY_CONTEXT]
|
||||
|
||||
[GMAIL_CONTEXT]
|
||||
{gmail skill memory}
|
||||
[/GMAIL_CONTEXT]
|
||||
|
||||
{notion_context if present}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Namespace Conventions
|
||||
|
||||
| Context | Namespace pattern | Set by |
|
||||
| ------------------------------ | ----------------- | ---------------------------------------------------------- |
|
||||
| Skill sync (OAuth / periodic) | `{skill_id}` | `store_skill_sync` — uses `skill_id` directly as namespace |
|
||||
| Skill memory clear | `{skill_id}` | `clear_skill_memory` |
|
||||
| Conversation recall | `conversations` | `chat_send_inner` hardcoded |
|
||||
| Skill context recall (in chat) | `{skill_id}` | `chat_send_inner` per-skill loop |
|
||||
| E2E test | `sdk-rust-e2e` | `example_e2e.rs` |
|
||||
|
||||
---
|
||||
|
||||
### All SDK Calls in the Project
|
||||
|
||||
| Location | SDK method called | Purpose |
|
||||
| ----------------------------------------- | ---------------------------------- | --------------------------------------- |
|
||||
| `memory/mod.rs::store_skill_sync` | `insert_memory` | Write skill sync data |
|
||||
| `memory/mod.rs::store_skill_sync` | `ingestion_job_status` (poll loop) | Wait for ingestion to complete |
|
||||
| `memory/mod.rs::query_skill_context` | `query_memory` | RAG query for skill context |
|
||||
| `memory/mod.rs::recall_skill_context` | `recall_memory` | Recall synthesised context |
|
||||
| `memory/mod.rs::recall_namespace_context` | `recall_memory` | Direct namespace recall |
|
||||
| `memory/mod.rs::query_namespace_context` | `query_memory` | Direct namespace query |
|
||||
| `memory/mod.rs::list_documents` | `list_documents` | List ingested documents |
|
||||
| `memory/mod.rs::delete_document` | `delete_document` | Remove a document |
|
||||
| `memory/mod.rs::clear_skill_memory` | `delete_memory` | Wipe skill namespace on disconnect |
|
||||
| `commands/chat.rs` (step 2) | via `recall_skill_context` | Inject conversation history into prompt |
|
||||
| `commands/chat.rs` (step 2b) | via `recall_skill_context` | Inject per-skill context into prompt |
|
||||
@@ -42,6 +42,8 @@ export default [
|
||||
globals: {
|
||||
// Browser globals
|
||||
window: 'readonly',
|
||||
localStorage: 'readonly',
|
||||
sessionStorage: 'readonly',
|
||||
document: 'readonly',
|
||||
navigator: 'readonly',
|
||||
console: 'readonly',
|
||||
|
||||
+19
-21
@@ -1,34 +1,34 @@
|
||||
---
|
||||
description: >-
|
||||
AlphaHuman is a personal AI assistant that runs natively across desktop,
|
||||
OpenHuman is a personal AI assistant that runs natively across desktop,
|
||||
mobile, and web that connects your communication platforms, tools, and
|
||||
workflows into a single intelligence layer you control.
|
||||
icon: diamond
|
||||
---
|
||||
|
||||
# Welcome to AlphaHuman
|
||||
# Welcome to OpenHuman
|
||||
|
||||
AlphaHuman is the first open-source AI agent with Big Data capabilities and a personalized subconscious mind. Built on the OpenClaw architecture and licensed under GNU GPL3, AlphaHuman is designed to close the gap between what AI models can do and what they actually know about you.
|
||||
OpenHuman is the first open-source AI agent with Big Data capabilities and a personalized subconscious mind. Built on the OpenClaw architecture and licensed under GNU GPL3, OpenHuman is designed to close the gap between what AI models can do and what they actually know about you.
|
||||
|
||||
Every AI model in the world, all 200+ of them, shares the same fundamental limitation. They are stateless. You type a prompt, get a response, and the context evaporates. Even the ones with "memory" store a few bullet points. A few bullet points is a sticky note, not intelligence.
|
||||
|
||||
AlphaHuman solves this with two core innovations:
|
||||
OpenHuman solves this with two core innovations:
|
||||
|
||||
<figure><img src=".gitbook/assets/V02 — Two Innovations@2x.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
**Neocortex**, a human-like memory engine that can accurately work with over 1 billion tokens. Neocortex indexes 10 million tokens in under 10 seconds, costs $1 to index 5 million tokens, and runs on a MacBook Air CPU with zero LLM dependency. Neocortex goes beyond vector databases. It understands time, entities, and relationships, and it models memory the way the human brain does: by compressing, forgetting strategically, and building knowledge graphs.
|
||||
|
||||
**A personalized subconscious system** inspired by the Purkinje cell, a specialized neuron in the human brain responsible for random thoughts and consciousness. AlphaHuman's subconscious triggers over 10,000 memory recall loops per day for under $1, producing proactive insights, pattern recognition, and emergent "thoughts" that feed into a self-learning loop.
|
||||
**A personalized subconscious system** inspired by the Purkinje cell, a specialized neuron in the human brain responsible for random thoughts and consciousness. OpenHuman's subconscious triggers over 10,000 memory recall loops per day for under $1, producing proactive insights, pattern recognition, and emergent "thoughts" that feed into a self-learning loop.
|
||||
|
||||
Together, these systems turn AlphaHuman into something fundamentally different from a chatbot. It is an AI agent that consumes large amounts of personal data at low cost, maintains a persistent and evolving understanding of your world, and takes proactive actions on your behalf.
|
||||
Together, these systems turn OpenHuman into something fundamentally different from a chatbot. It is an AI agent that consumes large amounts of personal data at low cost, maintains a persistent and evolving understanding of your world, and takes proactive actions on your behalf.
|
||||
|
||||
{% hint style="info" %}
|
||||
AlphaHuman is not AGI. But it is a meaningful architectural step closer to it, with better memory and better orchestration for memory, taking direct inspiration from the human brain.
|
||||
OpenHuman is not AGI. But it is a meaningful architectural step closer to it, with better memory and better orchestration for memory, taking direct inspiration from the human brain.
|
||||
{% endhint %}
|
||||
|
||||
## What AlphaHuman does
|
||||
## What OpenHuman does
|
||||
|
||||
AlphaHuman connects to your communication platforms, tools, and workflows, and compresses that information into structured intelligence any AI can act on.
|
||||
OpenHuman connects to your communication platforms, tools, and workflows, and compresses that information into structured intelligence any AI can act on.
|
||||
|
||||
It **compresses context** across your connected sources, turning millions of tokens of organizational noise into a structured knowledge graph of entities, relationships, and temporal chains.
|
||||
|
||||
@@ -38,29 +38,27 @@ It **thinks proactively** through its subconscious system, making connections an
|
||||
|
||||
It **preserves privacy** by design. Raw data stays on your device. Encryption keys never leave the device. Only compressed metadata and summaries are processed server-side.
|
||||
|
||||
|
||||
|
||||
## Who it's for
|
||||
|
||||
AlphaHuman is built for people and teams who operate across many conversations and tools, and feel the cost of it.
|
||||
OpenHuman is built for people and teams who operate across many conversations and tools, and feel the cost of it.
|
||||
|
||||
* **Developers and power users** in the AI ecosystem, especially those using OpenClaw, CrewAI, and similar agentic frameworks, who need a memory and context layer that actually scales.
|
||||
* **High-volume communicators** who miss decisions, context, and follow-ups buried in message noise across multiple platforms.
|
||||
* **Traders and analysts** who need fast signal extraction and risk awareness across information channels, both on-chain and off-chain.
|
||||
* **Distributed teams** who make decisions in chat but need structured follow-through in external tools.
|
||||
- **Developers and power users** in the AI ecosystem, especially those using OpenClaw, CrewAI, and similar agentic frameworks, who need a memory and context layer that actually scales.
|
||||
- **High-volume communicators** who miss decisions, context, and follow-ups buried in message noise across multiple platforms.
|
||||
- **Traders and analysts** who need fast signal extraction and risk awareness across information channels, both on-chain and off-chain.
|
||||
- **Distributed teams** who make decisions in chat but need structured follow-through in external tools.
|
||||
|
||||
## What AlphaHuman does not do
|
||||
## What OpenHuman does not do
|
||||
|
||||
AlphaHuman does not claim to be AGI. It does not send messages automatically or impersonate you. It does not store your raw message data long-term. It does not train on your data.
|
||||
OpenHuman does not claim to be AGI. It does not send messages automatically or impersonate you. It does not store your raw message data long-term. It does not train on your data.
|
||||
|
||||
{% hint style="info" %}
|
||||
Privacy is a core architectural decision, not a checkbox. The full privacy design is covered in Privacy & Security.
|
||||
{% endhint %}
|
||||
|
||||
## How to think about AlphaHuman
|
||||
## How to think about OpenHuman
|
||||
|
||||
Think of it this way: ChatGPT, Claude, Gemini, and every other model are the brain. They are brilliant at reasoning, generation, and analysis. But they are amnesiac. They know nothing about your actual life.
|
||||
|
||||
AlphaHuman is the memory and the subconscious that makes those brains actually useful. It is the Big Data layer for AI: an always-on context engine that compresses your entire organizational life into intelligence any AI can act on.
|
||||
OpenHuman is the memory and the subconscious that makes those brains actually useful. It is the Big Data layer for AI: an always-on context engine that compresses your entire organizational life into intelligence any AI can act on.
|
||||
|
||||
Your AI is smart. It just does not know you. AlphaHuman fixes that.
|
||||
Your AI is smart. It just does not know you. OpenHuman fixes that.
|
||||
|
||||
+15
-15
@@ -2,33 +2,33 @@
|
||||
|
||||
## Overview
|
||||
|
||||
* [Welcome to AlphaHuman](README.md)
|
||||
* [How It Works](overview/how-it-works.md)
|
||||
* [Getting Started](overview/getting-started.md)
|
||||
- [Welcome to OpenHuman](README.md)
|
||||
- [How It Works](overview/how-it-works.md)
|
||||
- [Getting Started](overview/getting-started.md)
|
||||
|
||||
## Technology
|
||||
|
||||
* [Neocortex](technology/neocortex.md)
|
||||
* [The Subconscious](technology/the-subconscious.md)
|
||||
* [Architecture](technology/architecture.md)
|
||||
- [Neocortex](technology/neocortex.md)
|
||||
- [The Subconscious](technology/the-subconscious.md)
|
||||
- [Architecture](technology/architecture.md)
|
||||
|
||||
## Product
|
||||
|
||||
* [Platform & Availability](product/platform.md)
|
||||
* [Skills & Integrations](product/skills-and-integrations.md)
|
||||
* [Teams & Organizations](product/teams.md)
|
||||
* [Privacy & Security](product/privacy-and-security.md)
|
||||
* [Pricing](product/pricing.md)
|
||||
- [Platform & Availability](product/platform.md)
|
||||
- [Skills & Integrations](product/skills-and-integrations.md)
|
||||
- [Teams & Organizations](product/teams.md)
|
||||
- [Privacy & Security](product/privacy-and-security.md)
|
||||
- [Pricing](product/pricing.md)
|
||||
|
||||
## Use Cases
|
||||
|
||||
* [Overview](use-cases/overview.md)
|
||||
- [Overview](use-cases/overview.md)
|
||||
|
||||
## Resources
|
||||
|
||||
* [FAQ & Troubleshooting](resources/faq.md)
|
||||
- [FAQ & Troubleshooting](resources/faq.md)
|
||||
|
||||
## Legal
|
||||
|
||||
* [Terms & Conditions](legal/terms-of-use.md)
|
||||
* [Privacy Policy](legal/privacy-policy.md)
|
||||
- [Terms & Conditions](legal/terms-of-use.md)
|
||||
- [Privacy Policy](legal/privacy-policy.md)
|
||||
|
||||
@@ -67,4 +67,3 @@ Depending on your location, you may have rights to access, correct, delete, rest
|
||||
## Changes to This Policy
|
||||
|
||||
We may update this Privacy Policy from time to time. Material changes will be communicated as required by law. Changes will not apply retroactively in a manner that reduces existing privacy protections.
|
||||
|
||||
|
||||
@@ -4,46 +4,46 @@ icon: play
|
||||
|
||||
# Getting Started
|
||||
|
||||
This section walks you through setting up AlphaHuman and running your first request.
|
||||
This section walks you through setting up OpenHuman and running your first request.
|
||||
|
||||
AlphaHuman is open source under the GNU GPL3 license. The codebase is available at [github.com/tinyhumansai/alphahuman](https://github.com/tinyhumansai/alphahuman). You can self-host, contribute, or simply use the hosted version.
|
||||
OpenHuman is open source under the GNU GPL3 license. The codebase is available at [github.com/tinyhumansai/openhuman](https://github.com/tinyhumansai/openhuman). You can self-host, contribute, or simply use the hosted version.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Download & Install
|
||||
|
||||
AlphaHuman runs natively on:
|
||||
OpenHuman runs natively on:
|
||||
|
||||
* **macOS** (Intel and Apple Silicon)
|
||||
* **Windows** (x64 and ARM64)
|
||||
* **Linux** (x64 and ARM64: AppImage and .deb)
|
||||
* **Android**
|
||||
* **iOS**
|
||||
* **Web** (any modern browser)
|
||||
- **macOS** (Intel and Apple Silicon)
|
||||
- **Windows** (x64 and ARM64)
|
||||
- **Linux** (x64 and ARM64: AppImage and .deb)
|
||||
- **Android**
|
||||
- **iOS**
|
||||
- **Web** (any modern browser)
|
||||
|
||||
Download the app for your platform from the official AlphaHuman website, or use the web version directly in your browser.
|
||||
Download the app for your platform from the official OpenHuman website, or use the web version directly in your browser.
|
||||
|
||||
The native app has a small footprint, starts fast, and uses your operating system's secure credential storage. The web version provides the same core functionality when a native install is not practical.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Create Your Account
|
||||
|
||||
When you first open AlphaHuman, you will be asked to sign in. Multiple sign-in options are available, including social login providers.
|
||||
When you first open OpenHuman, you will be asked to sign in. Multiple sign-in options are available, including social login providers.
|
||||
|
||||
After signing in, you may be placed on a waitlist depending on rollout status. The waitlist is used to manage access during launch and early scaling.
|
||||
|
||||
{% hint style="info" %}
|
||||
**No permanent lock-in.** Creating an account does not grant AlphaHuman ongoing access to anything. All processing still requires explicit actions from you later.
|
||||
**No permanent lock-in.** Creating an account does not grant OpenHuman ongoing access to anything. All processing still requires explicit actions from you later.
|
||||
{% endhint %}
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Connect Your First Source
|
||||
|
||||
AlphaHuman works by connecting to your existing tools and platforms. Each connection expands your knowledge graph, giving Neocortex more data to compress and reason over. You choose what to connect, and you can revoke access at any time.
|
||||
OpenHuman works by connecting to your existing tools and platforms. Each connection expands your knowledge graph, giving Neocortex more data to compress and reason over. You choose what to connect, and you can revoke access at any time.
|
||||
|
||||
**Telegram:** Connect your Telegram account to analyze conversations, extract signals, and generate summaries across your chats and groups. AlphaHuman supports the full range of Telegram capabilities: chat management, message search, contact management, group and channel administration, reactions, polls, inline buttons, and more.
|
||||
**Telegram:** Connect your Telegram account to analyze conversations, extract signals, and generate summaries across your chats and groups. OpenHuman supports the full range of Telegram capabilities: chat management, message search, contact management, group and channel administration, reactions, polls, inline buttons, and more.
|
||||
|
||||
**Notion:** Connect Notion to export structured outputs like summaries, action items, decisions, and workflow records into your workspace.
|
||||
|
||||
@@ -53,39 +53,39 @@ AlphaHuman works by connecting to your existing tools and platforms. Each connec
|
||||
|
||||
All integrations are optional. You can start with one source and add more later. The more sources you connect, the more powerful the intelligence becomes. Each connection is independently revocable.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Run Your First Request
|
||||
|
||||
Once a source is connected, you can start asking AlphaHuman questions using the command input.
|
||||
Once a source is connected, you can start asking OpenHuman questions using the command input.
|
||||
|
||||
Try prompts like:
|
||||
|
||||
* **"Summarize what I missed today"**
|
||||
* **"What are the key decisions from this week?"**
|
||||
* **"Extract action items from my recent conversations"**
|
||||
* **"What topics are trending across my groups?"**
|
||||
- **"Summarize what I missed today"**
|
||||
- **"What are the key decisions from this week?"**
|
||||
- **"Extract action items from my recent conversations"**
|
||||
- **"What topics are trending across my groups?"**
|
||||
|
||||
AlphaHuman processes only the data needed to answer your request, produces an output, and presents it for your review. If the output feels too broad or too shallow, narrow the scope. Specify a particular conversation, time range, or intent.
|
||||
OpenHuman processes only the data needed to answer your request, produces an output, and presents it for your review. If the output feels too broad or too shallow, narrow the scope. Specify a particular conversation, time range, or intent.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Explore Skills & Integrations
|
||||
|
||||
After your first request, explore what else AlphaHuman can do:
|
||||
After your first request, explore what else OpenHuman can do:
|
||||
|
||||
* **Skills** extend the assistant's capabilities, fetching external data, running scheduled tasks, processing information, and writing outputs to connected tools
|
||||
* **Integrations** let you push structured results to Notion, Google Sheets, and other tools
|
||||
* **Workflows** turn conversation decisions into trackable actions you can follow through on
|
||||
- **Skills** extend the assistant's capabilities, fetching external data, running scheduled tasks, processing information, and writing outputs to connected tools
|
||||
- **Integrations** let you push structured results to Notion, Google Sheets, and other tools
|
||||
- **Workflows** turn conversation decisions into trackable actions you can follow through on
|
||||
|
||||
Learn more in [Skills & Integrations](../product/skills-and-integrations.md).
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Join the Community
|
||||
|
||||
AlphaHuman is in early alpha. Feedback and contributions make a real difference at this stage.
|
||||
OpenHuman is in early alpha. Feedback and contributions make a real difference at this stage.
|
||||
|
||||
Join the Discord community to connect with other users, share feedback, report issues, and contribute to the project. Early users get free usage as part of the alpha program.
|
||||
|
||||
**GitHub:** [github.com/tinyhumansai/alphahuman](https://github.com/tinyhumansai/alphahuman)
|
||||
**GitHub:** [github.com/tinyhumansai/openhuman](https://github.com/tinyhumansai/openhuman)
|
||||
|
||||
@@ -4,9 +4,9 @@ icon: brain
|
||||
|
||||
# How It Works
|
||||
|
||||
AlphaHuman is built on three technology pillars: a memory engine called Neocortex, a subconscious system inspired by human neuroscience, and a privacy-preserving architecture that keeps raw data on your device. Understanding how these work together is understanding how AlphaHuman thinks.
|
||||
OpenHuman is built on three technology pillars: a memory engine called Neocortex, a subconscious system inspired by human neuroscience, and a privacy-preserving architecture that keeps raw data on your device. Understanding how these work together is understanding how OpenHuman thinks.
|
||||
|
||||
### The problem AlphaHuman solves
|
||||
### The problem OpenHuman solves
|
||||
|
||||
Current AI systems fall into the category of Artificial Narrow Intelligence (ANI). They perform well within bounded domains, but they depend on carefully designed architectures and human-defined operational boundaries. They lack three things needed to get closer to general intelligence: persistent memory at scale, a form of consciousness or instinct, and the ability to ingest data without becoming inaccurate or expensive.
|
||||
|
||||
@@ -14,7 +14,7 @@ Research from Google's Titans project demonstrates the core issue clearly. As LL
|
||||
|
||||
<figure><img src="../.gitbook/assets/V04_The_ANI_Problem@2x.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
AlphaHuman solves this in two steps.
|
||||
OpenHuman solves this in two steps.
|
||||
|
||||
#### Step 1: Neocortex, the memory engine
|
||||
|
||||
@@ -50,13 +50,13 @@ Additional capabilities of Neocortex:
|
||||
|
||||
#### Step 2: The personalized subconscious
|
||||
|
||||
With good memory and good recall, AlphaHuman can do something no other AI agent does: maintain a personalized subconscious.
|
||||
With good memory and good recall, OpenHuman can do something no other AI agent does: maintain a personalized subconscious.
|
||||
|
||||
In the human brain, there is a specialized neuron called the Purkinje cell. It is mainly responsible for random thoughts and plays a significant role in consciousness. The human brain has both a conscious and subconscious mind that work together to build intelligence. Most agentic systems follow the conscious mind model only. They wait for instructions and execute them. They cannot think on their own.
|
||||
|
||||
<figure><img src="../.gitbook/assets/V07_Purkinje_Cell_to_Subconscious@2x.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Inspired by the Purkinje cell, AlphaHuman uses Neocortex to periodically trigger global memory recalls. These recalls are fed into a subconscious loop that produces actions, confirmations, or new connections. Memory recalls are cheap, fast, and happen over 10,000 times a day for less than $1.
|
||||
Inspired by the Purkinje cell, OpenHuman uses Neocortex to periodically trigger global memory recalls. These recalls are fed into a subconscious loop that produces actions, confirmations, or new connections. Memory recalls are cheap, fast, and happen over 10,000 times a day for less than $1.
|
||||
|
||||
The result is an AI that does not just respond to your prompts. It thinks about your data in the background. It makes connections you did not ask for. It surfaces patterns and risks proactively.
|
||||
|
||||
@@ -64,7 +64,7 @@ The success metric for the subconscious is what the team calls the "mirror test"
|
||||
|
||||
### How the pieces connect
|
||||
|
||||
When you use AlphaHuman, here is what happens:
|
||||
When you use OpenHuman, here is what happens:
|
||||
|
||||
<figure><img src="../.gitbook/assets/V08_How_Pieces_Connect@2x.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
@@ -74,13 +74,13 @@ When you use AlphaHuman, here is what happens:
|
||||
|
||||
**The subconscious runs.** Thousands of recall loops per day surface proactive insights, track evolving patterns, and update the knowledge graph.
|
||||
|
||||
**You interact naturally.** Ask anything about your life, your team, your projects. Not general knowledge. Your knowledge. What did your team decide? What is the status? What did you miss? AlphaHuman already knows.
|
||||
**You interact naturally.** Ask anything about your life, your team, your projects. Not general knowledge. Your knowledge. What did your team decide? What is the status? What did you miss? OpenHuman already knows.
|
||||
|
||||
**Privacy is maintained.** Raw data stays on device, encrypted with AES-256-GCM. Encryption keys never leave the device. Only compressed metadata and summaries are processed server-side.
|
||||
|
||||
### The architecture: OpenClaw foundation
|
||||
|
||||
AlphaHuman is built on top of the OpenClaw architecture and is open-sourced under the GNU GPL3 license. The full codebase is publicly available on GitHub.
|
||||
OpenHuman is built on top of the OpenClaw architecture and is open-sourced under the GNU GPL3 license. The full codebase is publicly available on GitHub.
|
||||
|
||||
The architecture uses multi-agent orchestration, where specialized agents are dynamically spawned for specific tasks rather than relying on one monolithic model. An orchestrator agent manages routing, personality, and context distribution. Specialist agents handle specific domains: communication analysis, document synthesis, task management, trading. These agents execute in parallel, not sequentially, for real-time responsiveness.
|
||||
|
||||
@@ -88,8 +88,8 @@ All agents share a common compressed context provided by Neocortex. This effecti
|
||||
|
||||
### Limitations
|
||||
|
||||
AlphaHuman works with probabilistic models. It may occasionally miss nuance, misinterpret sarcasm, or over-prioritize certain messages. This is more likely in highly informal conversations, fast-moving threads, or contexts with limited data.
|
||||
OpenHuman works with probabilistic models. It may occasionally miss nuance, misinterpret sarcasm, or over-prioritize certain messages. This is more likely in highly informal conversations, fast-moving threads, or contexts with limited data.
|
||||
|
||||
AlphaHuman is not AGI. It is a meaningful step closer, with better memory and better orchestration for memory, taking inspiration from the human brain. But human judgment still matters. AlphaHuman helps you think faster. It does not think for you.
|
||||
OpenHuman is not AGI. It is a meaningful step closer, with better memory and better orchestration for memory, taking inspiration from the human brain. But human judgment still matters. OpenHuman helps you think faster. It does not think for you.
|
||||
|
||||
Everything is in early alpha. Feedback and contributions are welcomed.
|
||||
|
||||
@@ -6,7 +6,7 @@ icon: layer-plus
|
||||
|
||||
OpenHuman is a native **desktop** application. It is not a web-only tool, browser extension, or Electron wrapper. It is built for performance, security, and a small footprint on the machines where we officially support it today.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Supported today: desktop
|
||||
|
||||
@@ -20,7 +20,7 @@ OpenHuman ships native installers for:
|
||||
|
||||
**Android, iOS, and a standalone web client are not supported** in documentation or releases yet. The codebase may contain experimental mobile or web targets; they are out of scope for current user-facing docs.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Why Native Matters
|
||||
|
||||
@@ -32,7 +32,7 @@ OpenHuman is built as a native application rather than a web wrapper for three r
|
||||
|
||||
**OS-level security.** On desktop platforms, OpenHuman stores credentials in your operating system's secure keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). Sensitive data never sits in browser storage or plain text files.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Architecture at a Glance
|
||||
|
||||
@@ -48,7 +48,7 @@ OpenHuman operates across three layers:
|
||||
The intelligence layer is not part of the client application. It performs analysis, coordination, and trust scoring separately from the frontend.
|
||||
{% endhint %}
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Real-Time Communication
|
||||
|
||||
@@ -56,7 +56,7 @@ OpenHuman maintains a persistent connection between the application and the inte
|
||||
|
||||
The connection is designed for resilience. If the network drops, OpenHuman reconnects automatically with progressive backoff. There is no manual reconnection process.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Offline Behavior
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ icon: layer-plus
|
||||
|
||||
# Platform & Availability
|
||||
|
||||
AlphaHuman is a native application that runs on six platforms from a single codebase. It is not a web-only tool, browser extension, or Electron wrapper. It is built for performance, security, and a small footprint on every device you use.
|
||||
OpenHuman is a native application that runs on six platforms from a single codebase. It is not a web-only tool, browser extension, or Electron wrapper. It is built for performance, security, and a small footprint on every device you use.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Six Platforms, One Experience
|
||||
|
||||
AlphaHuman compiles to native binaries for each supported platform:
|
||||
OpenHuman compiles to native binaries for each supported platform:
|
||||
|
||||
| Platform | Architectures | Distribution |
|
||||
| ----------- | -------------------- | -------------- |
|
||||
@@ -23,46 +23,46 @@ AlphaHuman compiles to native binaries for each supported platform:
|
||||
|
||||
Your account, connected sources, preferences, and settings sync across all platforms. You can start a request on your desktop and review the output on your phone.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Why Native Matters
|
||||
|
||||
AlphaHuman is built as a native application rather than a web wrapper for three reasons.
|
||||
OpenHuman is built as a native application rather than a web wrapper for three reasons.
|
||||
|
||||
**Small footprint.** The app is lightweight. A fraction of the size of typical communication tools. It starts in under a second and uses minimal memory, so it stays out of the way when running alongside other demanding applications.
|
||||
|
||||
**Fast startup.** There is no browser engine to initialize. The app launches quickly and is ready to accept requests immediately.
|
||||
|
||||
**OS-level security.** On desktop platforms, AlphaHuman stores credentials in your operating system's secure keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). Sensitive data never sits in browser storage or plain text files.
|
||||
**OS-level security.** On desktop platforms, OpenHuman stores credentials in your operating system's secure keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). Sensitive data never sits in browser storage or plain text files.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Architecture at a Glance
|
||||
|
||||
AlphaHuman operates across three layers:
|
||||
OpenHuman operates across three layers:
|
||||
|
||||
**Application layer.** The native app on your device handles the interface, user input, local state, credential management, and skill execution. This layer is responsible for everything you see and interact with.
|
||||
|
||||
**Intelligence layer.** AlphaHuman's analysis, coordination, and intelligence systems run as a secure backend service. When a request requires deeper language processing, it is handled here. This layer is operated and maintained by AlphaHuman.
|
||||
**Intelligence layer.** OpenHuman's analysis, coordination, and intelligence systems run as a secure backend service. When a request requires deeper language processing, it is handled here. This layer is operated and maintained by OpenHuman.
|
||||
|
||||
**External services.** Connected tools and platforms:Telegram, Notion, Google Sheets, and others are accessed only when you explicitly request it. AlphaHuman acts as a bridge between your sources and the intelligence layer, not as a replacement for any of them.
|
||||
**External services.** Connected tools and platforms:Telegram, Notion, Google Sheets, and others are accessed only when you explicitly request it. OpenHuman acts as a bridge between your sources and the intelligence layer, not as a replacement for any of them.
|
||||
|
||||
{% hint style="info" %}
|
||||
The intelligence layer is not part of the client application. It performs analysis, coordination, and trust scoring separately from the frontend.
|
||||
{% endhint %}
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Real-Time Communication
|
||||
|
||||
AlphaHuman maintains a persistent connection between the application and the intelligence layer. This means responses arrive in real time as they are generated. You see outputs streaming, not loading.
|
||||
OpenHuman maintains a persistent connection between the application and the intelligence layer. This means responses arrive in real time as they are generated. You see outputs streaming, not loading.
|
||||
|
||||
The connection is designed for resilience. If the network drops, AlphaHuman reconnects automatically with progressive backoff. There is no manual reconnection process.
|
||||
The connection is designed for resilience. If the network drops, OpenHuman reconnects automatically with progressive backoff. There is no manual reconnection process.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Offline Behavior
|
||||
|
||||
AlphaHuman's local state persists on your device. Your preferences, settings, and connected source configurations remain available even when you are offline.
|
||||
OpenHuman's local state persists on your device. Your preferences, settings, and connected source configurations remain available even when you are offline.
|
||||
|
||||
Full analysis and intelligence features require a network connection, since they depend on the intelligence layer. When connectivity is restored, the app resumes normal operation without requiring you to re-authenticate or reconfigure.
|
||||
|
||||
+16
-16
@@ -4,19 +4,19 @@ icon: sack-dollar
|
||||
|
||||
# Pricing
|
||||
|
||||
AlphaHuman is priced as a SaaS product for individuals and teams that rely on high-volume communication and need clarity, coordination, and safety across their tools. Pricing reflects the value of reduced cognitive load and better signal quality, not raw message volume.
|
||||
OpenHuman is priced as a SaaS product for individuals and teams that rely on high-volume communication and need clarity, coordination, and safety across their tools. Pricing reflects the value of reduced cognitive load and better signal quality, not raw message volume.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Individual Plans
|
||||
|
||||
Individual plans are designed for power users who want help managing high-volume activity across multiple conversations and connected sources.
|
||||
|
||||
Core analysis functionality is included so users can understand AlphaHuman's value before committing. Deeper features, longer context windows, persistent workflows, richer integrations, and advanced intelligence are available in higher tiers.
|
||||
Core analysis functionality is included so users can understand OpenHuman's value before committing. Deeper features, longer context windows, persistent workflows, richer integrations, and advanced intelligence are available in higher tiers.
|
||||
|
||||
Plans are tiered to allow users to start lightweight and expand as their needs grow.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Team Plans
|
||||
|
||||
@@ -26,34 +26,34 @@ Team plans include shared workflows, community-level intelligence, coordination
|
||||
|
||||
Individual user privacy is preserved even in shared team environments.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Credit System
|
||||
|
||||
AlphaHuman uses a credit-based system for usage-metered features.
|
||||
OpenHuman uses a credit-based system for usage-metered features.
|
||||
|
||||
* Credits are consumed when you use analysis, intelligence, and processing features
|
||||
* Oldest credits are consumed first, encouraging usage before expiry
|
||||
* Credits can be earned through the referral program, in addition to purchase
|
||||
* Every credit transaction is tracked in an auditable ledger
|
||||
- Credits are consumed when you use analysis, intelligence, and processing features
|
||||
- Oldest credits are consumed first, encouraging usage before expiry
|
||||
- Credits can be earned through the referral program, in addition to purchase
|
||||
- Every credit transaction is tracked in an auditable ledger
|
||||
|
||||
Credits provide flexibility as you pay for what you use, and you can supplement your plan with earned credits from referrals.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Payment Methods
|
||||
|
||||
AlphaHuman supports standard and cryptocurrency payment options.
|
||||
OpenHuman supports standard and cryptocurrency payment options.
|
||||
|
||||
* **Card payments:** Standard subscription billing with the ability to upgrade, downgrade, or cancel at any time
|
||||
* **Cryptocurrency:** Alternative payment path for users who prefer crypto
|
||||
- **Card payments:** Standard subscription billing with the ability to upgrade, downgrade, or cancel at any time
|
||||
- **Cryptocurrency:** Alternative payment path for users who prefer crypto
|
||||
|
||||
Changes to your plan take effect immediately. Cancellation does not affect outputs already exported to external tools.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Access During Launch
|
||||
|
||||
During the initial launch phase, access to AlphaHuman may be gated through a waitlist. This is done to manage platform stability and collect feedback from early users.
|
||||
During the initial launch phase, access to OpenHuman may be gated through a waitlist. This is done to manage platform stability and collect feedback from early users.
|
||||
|
||||
Waitlist access does not imply long-term pricing commitments. Pricing and plan boundaries may evolve during this phase as usage patterns become clearer.
|
||||
|
||||
@@ -4,71 +4,71 @@ icon: shield
|
||||
|
||||
# Privacy & Security
|
||||
|
||||
AlphaHuman operates on a principle of **zero-knowledge intelligence**. The system is architecturally designed so that your raw data never needs to leave your device. Neocortex compresses your data locally into structured metadata and summaries. Only this compressed output is processed server-side. Your AI has months of context about your entire organizational life. Your raw data has never touched our servers.
|
||||
OpenHuman operates on a principle of **zero-knowledge intelligence**. The system is architecturally designed so that your raw data never needs to leave your device. Neocortex compresses your data locally into structured metadata and summaries. Only this compressed output is processed server-side. Your AI has months of context about your entire organizational life. Your raw data has never touched our servers.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Privacy by Design
|
||||
|
||||
AlphaHuman operates on a principle of **zero retention** for message content. When you make a request, the relevant data is processed to produce an output, and the source content is discarded afterward.
|
||||
OpenHuman operates on a principle of **zero retention** for message content. When you make a request, the relevant data is processed to produce an output, and the source content is discarded afterward.
|
||||
|
||||
**No long-term message storage.** AlphaHuman does not maintain a persistent archive of your conversations. Context is reconstructed from your connected sources when needed.
|
||||
**No long-term message storage.** OpenHuman does not maintain a persistent archive of your conversations. Context is reconstructed from your connected sources when needed.
|
||||
|
||||
**No training on your data.** Your conversations, analysis results, and personal information are never used to train AI models or improve systems. Your data serves you and only you.
|
||||
|
||||
**OS-level credential storage.** On desktop platforms, AlphaHuman uses your operating system's secure keychain to store credentials and sensitive tokens. Credentials are never stored in plain text, browser storage, or application-level databases.
|
||||
**OS-level credential storage.** On desktop platforms, OpenHuman uses your operating system's secure keychain to store credentials and sensitive tokens. Credentials are never stored in plain text, browser storage, or application-level databases.
|
||||
|
||||
**On-device where possible.** Interface rendering, input handling, local state management, and credential operations all happen on your device. Only tasks requiring deeper language processing are handled server-side, under the same privacy constraints.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Permissions and Access Control
|
||||
|
||||
AlphaHuman operates on an **explicit-access model**. It only accesses data when you issue a request, and only the data needed to fulfill that request.
|
||||
OpenHuman operates on an **explicit-access model**. It only accesses data when you issue a request, and only the data needed to fulfill that request.
|
||||
|
||||
### Request-Scoped Access
|
||||
|
||||
Access is determined by your requests, not by background monitoring. If you ask AlphaHuman to summarize a specific conversation, only that conversation is processed. If you do not reference a source, it is not accessed.
|
||||
Access is determined by your requests, not by background monitoring. If you ask OpenHuman to summarize a specific conversation, only that conversation is processed. If you do not reference a source, it is not accessed.
|
||||
|
||||
AlphaHuman does not silently expand its access over time. There is no progressive permission creep.
|
||||
OpenHuman does not silently expand its access over time. There is no progressive permission creep.
|
||||
|
||||
### Source-Specific Permissions
|
||||
|
||||
Each connected source has its own permission scope:
|
||||
|
||||
* **Telegram:** Read-only access. AlphaHuman can read messages from conversations you reference in a request. It cannot send messages, edit messages, react, join groups, or act on your behalf.
|
||||
* **Notion:** Write access to specific workspaces or pages you approve. AlphaHuman does not read unrelated documents.
|
||||
* **Google Sheets:** Write access to specific spreadsheets you approve. AlphaHuman does not read unrelated sheets.
|
||||
- **Telegram:** Read-only access. OpenHuman can read messages from conversations you reference in a request. It cannot send messages, edit messages, react, join groups, or act on your behalf.
|
||||
- **Notion:** Write access to specific workspaces or pages you approve. OpenHuman does not read unrelated documents.
|
||||
- **Google Sheets:** Write access to specific spreadsheets you approve. OpenHuman does not read unrelated sheets.
|
||||
|
||||
Integration permissions are limited to what is needed for the specific action you request.
|
||||
|
||||
### User-Initiated Actions Only
|
||||
|
||||
Every meaningful operation in AlphaHuman is user-initiated. Summaries, analysis, trust evaluation, workflow creation, and exports all require a direct request. There is no continuous background processing or monitoring.
|
||||
Every meaningful operation in OpenHuman is user-initiated. Summaries, analysis, trust evaluation, workflow creation, and exports all require a direct request. There is no continuous background processing or monitoring.
|
||||
|
||||
{% hint style="info" %}
|
||||
AlphaHuman is idle unless you ask it to do something.
|
||||
OpenHuman is idle unless you ask it to do something.
|
||||
{% endhint %}
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Revoking Access
|
||||
|
||||
You can revoke AlphaHuman's access to any connected source at any time.
|
||||
You can revoke OpenHuman's access to any connected source at any time.
|
||||
|
||||
* Disconnect a source from your settings
|
||||
* Remove integration permissions
|
||||
* Stop using the application entirely
|
||||
- Disconnect a source from your settings
|
||||
- Remove integration permissions
|
||||
- Stop using the application entirely
|
||||
|
||||
Once access is revoked, AlphaHuman immediately stops processing data from that source. There is no delayed or cached processing after revocation. Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written, but no new processing occurs.
|
||||
Once access is revoked, OpenHuman immediately stops processing data from that source. There is no delayed or cached processing after revocation. Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written, but no new processing occurs.
|
||||
|
||||
This makes AlphaHuman safe to test, pause, or stop using without residual exposure.
|
||||
This makes OpenHuman safe to test, pause, or stop using without residual exposure.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
AlphaHuman implements security at every layer of the system.
|
||||
OpenHuman implements security at every layer of the system.
|
||||
|
||||
**AES-256-GCM encryption.** All sensitive data stored locally is encrypted using AES-256-GCM. Encryption keys are derived from your credentials and stored in your operating system's secure keychain. Keys never leave the device. Even if server-side infrastructure were compromised, your raw data would remain inaccessible because it was never there.
|
||||
|
||||
@@ -76,11 +76,11 @@ AlphaHuman implements security at every layer of the system.
|
||||
|
||||
**Sandboxed skills.** Each skill runs in its own isolated execution environment with enforced memory and resource limits. Skills cannot access each other's data, the host system's file system, or your credentials.
|
||||
|
||||
**Encrypted transit.** All communication between the application and AlphaHuman's servers uses encrypted connections. No data travels in plain text.
|
||||
**Encrypted transit.** All communication between the application and OpenHuman's servers uses encrypted connections. No data travels in plain text.
|
||||
|
||||
**Short-lived tokens.** Authentication tokens are time-limited and single-use where applicable, reducing the window of exposure if a token is compromised.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## How Neocortex enables privacy
|
||||
|
||||
@@ -94,32 +94,32 @@ Compression itself becomes the privacy architecture. The raw data never needs to
|
||||
|
||||
## Trust & Risk Intelligence
|
||||
|
||||
AlphaHuman includes an intelligence layer designed to help you reason about credibility, information quality, and potential risks across your connected sources.
|
||||
OpenHuman includes an intelligence layer designed to help you reason about credibility, information quality, and potential risks across your connected sources.
|
||||
|
||||
### What It Does
|
||||
|
||||
**Scam and impersonation signals.** AlphaHuman can surface behavioral patterns associated with scams, impersonation, or coordinated abuse. These signals are derived from patterns observed across contexts, not from individual message content.
|
||||
**Scam and impersonation signals.** OpenHuman can surface behavioral patterns associated with scams, impersonation, or coordinated abuse. These signals are derived from patterns observed across contexts, not from individual message content.
|
||||
|
||||
**Contextual dynamic trust.** Trust is represented through aggregated artifacts, historical accuracy of claims, consistency of contributions, peer interaction patterns rather than static scores or universal ratings. Trust is always contextual: credibility in one domain does not automatically transfer to another.
|
||||
|
||||
**Advisory, not enforcement.** AlphaHuman does not ban users, remove messages, block actions, or enforce moderation decisions. Trust and risk outputs are advisory signals that inform your judgment. You decide how to act on them.
|
||||
**Advisory, not enforcement.** OpenHuman does not ban users, remove messages, block actions, or enforce moderation decisions. Trust and risk outputs are advisory signals that inform your judgment. You decide how to act on them.
|
||||
|
||||
### Scope
|
||||
|
||||
Trust and risk intelligence operates at different levels:
|
||||
|
||||
* **Personal:** Visible only to you. Your own analysis, trust assessments, and risk alerts.
|
||||
* **Community:** Aggregated patterns within a group or organization, supporting shared coordination and moderation. Never exposes individual message content.
|
||||
* **Network:** Anonymized patterns across the broader AlphaHuman user base, improving early detection of shared risks like recurring scam vectors. 
|
||||
- **Personal:** Visible only to you. Your own analysis, trust assessments, and risk alerts.
|
||||
- **Community:** Aggregated patterns within a group or organization, supporting shared coordination and moderation. Never exposes individual message content.
|
||||
- **Network:** Anonymized patterns across the broader OpenHuman user base, improving early detection of shared risks like recurring scam vectors. 
|
||||
|
||||
Information does not move between scopes without abstraction and anonymization.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Shared Environments
|
||||
|
||||
When AlphaHuman is used in team or community settings, privacy remains user-centric.
|
||||
When OpenHuman is used in team or community settings, privacy remains user-centric.
|
||||
|
||||
AlphaHuman does not grant administrators the ability to read private messages through another user's account. Each user's permissions apply only to their own connected sources.
|
||||
OpenHuman does not grant administrators the ability to read private messages through another user's account. Each user's permissions apply only to their own connected sources.
|
||||
|
||||
Community-level intelligence is derived from aggregated and anonymized signals, not from direct access to individual message content. Shared insights help teams coordinate effectively without compromising individual privacy.
|
||||
|
||||
@@ -4,25 +4,25 @@ icon: screwdriver
|
||||
|
||||
# Skills & Integrations
|
||||
|
||||
AlphaHuman extends its capabilities through two systems: a **skills engine** that adds new functionality to the assistant, and **integrations** that connect AlphaHuman to external tools. Together, they allow AlphaHuman to do more than analyze conversations; it can fetch data, run scheduled tasks, produce structured outputs, and write results to the tools you already use.
|
||||
OpenHuman extends its capabilities through two systems: a **skills engine** that adds new functionality to the assistant, and **integrations** that connect OpenHuman to external tools. Together, they allow OpenHuman to do more than analyze conversations; it can fetch data, run scheduled tasks, produce structured outputs, and write results to the tools you already use.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Skills Engine
|
||||
|
||||
Skills are sandboxed modules that run inside AlphaHuman's native application. Each skill is an isolated unit with its own execution environment, storage, and permissions. Skills extend what the assistant can do without requiring an app update.
|
||||
Skills are sandboxed modules that run inside OpenHuman's native application. Each skill is an isolated unit with its own execution environment, storage, and permissions. Skills extend what the assistant can do without requiring an app update.
|
||||
|
||||
When you make a request, AlphaHuman's AI automatically discovers which skills are available and decides whether to invoke them based on what you asked for. You do not need to manage skills manually. They are loaded, registered, and made available to the AI system transparently.
|
||||
When you make a request, OpenHuman's AI automatically discovers which skills are available and decides whether to invoke them based on what you asked for. You do not need to manage skills manually. They are loaded, registered, and made available to the AI system transparently.
|
||||
|
||||
### What Skills Can Do
|
||||
|
||||
Skills operate within defined boundaries. A skill can:
|
||||
|
||||
* **Fetch external data:** make HTTP requests to APIs, retrieve information from services, and bring data into AlphaHuman's context
|
||||
* **Run on a schedule:** execute at defined intervals using cron-style scheduling, enabling automated monitoring, reporting, or data collection
|
||||
* **Process and transform:** analyze, filter, or restructure data within its sandboxed environment, using its own local database for persistence
|
||||
* **Write outputs:** produce structured results that the AI can present to you or export through integrations
|
||||
* **Respond to events:** react to real-time events from the server, enabling workflows that trigger based on external conditions
|
||||
- **Fetch external data:** make HTTP requests to APIs, retrieve information from services, and bring data into OpenHuman's context
|
||||
- **Run on a schedule:** execute at defined intervals using cron-style scheduling, enabling automated monitoring, reporting, or data collection
|
||||
- **Process and transform:** analyze, filter, or restructure data within its sandboxed environment, using its own local database for persistence
|
||||
- **Write outputs:** produce structured results that the AI can present to you or export through integrations
|
||||
- **Respond to events:** react to real-time events from the server, enabling workflows that trigger based on external conditions
|
||||
|
||||
### Isolation and Safety
|
||||
|
||||
@@ -31,20 +31,20 @@ Each skill runs in its own sandboxed environment with enforced resource limits.
|
||||
Skills are discovered from a curated registry and filtered by platform compatibility. Only skills that support your current platform are loaded.
|
||||
|
||||
{% hint style="info" %}
|
||||
Skills extend AlphaHuman's capabilities without requiring trust beyond their declared scope. Each one is isolated, resource-limited, and independently revocable.
|
||||
Skills extend OpenHuman's capabilities without requiring trust beyond their declared scope. Each one is isolated, resource-limited, and independently revocable.
|
||||
{% endhint %}
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Integrations
|
||||
|
||||
Integrations connect AlphaHuman to external tools so structured outputs can live where your team already works. Integrations are not about importing data into AlphaHuman, they are about exporting intelligence out of it.
|
||||
Integrations connect OpenHuman to external tools so structured outputs can live where your team already works. Integrations are not about importing data into OpenHuman, they are about exporting intelligence out of it.
|
||||
|
||||
### Supported Integrations
|
||||
|
||||
**Telegram:** AlphaHuman connects to your Telegram account to read and analyze conversations, extract signals, summarize discussions, and generate context-aware responses. Access is scoped to the conversations you reference in your requests.
|
||||
**Telegram:** OpenHuman connects to your Telegram account to read and analyze conversations, extract signals, summarize discussions, and generate context-aware responses. Access is scoped to the conversations you reference in your requests.
|
||||
|
||||
**Notion:** Export summaries, action items, decisions, and workflow records to your Notion workspace. AlphaHuman writes structured documents that preserve the context of where outputs originated. Useful for building shared knowledge bases or living records.
|
||||
**Notion:** Export summaries, action items, decisions, and workflow records to your Notion workspace. OpenHuman writes structured documents that preserve the context of where outputs originated. Useful for building shared knowledge bases or living records.
|
||||
|
||||
**Google Sheets:** Export tabular data such as logs, reports, extracted metrics, or tracking records. Useful for lightweight analysis, reporting, and audit trails.
|
||||
|
||||
@@ -52,33 +52,33 @@ These integrations are optional and can be enabled or disabled at any time from
|
||||
|
||||
### How Data Moves
|
||||
|
||||
Data moves from AlphaHuman to external tools **only when you explicitly request it**.
|
||||
Data moves from OpenHuman to external tools **only when you explicitly request it**.
|
||||
|
||||
When a workflow, summary, or analysis is exported, AlphaHuman writes structured data, not raw conversation text. There is no continuous sync, no background polling, and no automatic data transfer. Each export is a deliberate action you initiate.
|
||||
When a workflow, summary, or analysis is exported, OpenHuman writes structured data, not raw conversation text. There is no continuous sync, no background polling, and no automatic data transfer. Each export is a deliberate action you initiate.
|
||||
|
||||
Integrations are write-oriented by default. AlphaHuman does not read from external tools unless a specific workflow requires it and you have approved that behavior.
|
||||
Integrations are write-oriented by default. OpenHuman does not read from external tools unless a specific workflow requires it and you have approved that behavior.
|
||||
|
||||
{% hint style="info" %}
|
||||
**You control what leaves AlphaHuman.** Nothing is exported to external tools without a clear, user-initiated action.
|
||||
**You control what leaves OpenHuman.** Nothing is exported to external tools without a clear, user-initiated action.
|
||||
{% endhint %}
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## From Conversation to Action
|
||||
|
||||
One of AlphaHuman's core capabilities is turning unstructured conversations into structured, actionable outputs.
|
||||
One of OpenHuman's core capabilities is turning unstructured conversations into structured, actionable outputs.
|
||||
|
||||
When discussions lead to decisions, commitments, or tasks, AlphaHuman can recognize these moments (when you ask it to analyze a conversation) and represent them as **workflows as** structured objects that capture what needs to happen, who is involved, and where the decision came from.
|
||||
When discussions lead to decisions, commitments, or tasks, OpenHuman can recognize these moments (when you ask it to analyze a conversation) and represent them as **workflows as** structured objects that capture what needs to happen, who is involved, and where the decision came from.
|
||||
|
||||
Workflows link back to the conversations they originated from, preserving intent and rationale. When connected to tools like Notion or Google Sheets, workflows can be exported without duplicating entire conversation histories.
|
||||
|
||||
Workflows exist to reduce coordination friction, not to replace dedicated project management systems. AlphaHuman does not auto-assign tasks, enforce deadlines, or create workflows without your input.
|
||||
Workflows exist to reduce coordination friction, not to replace dedicated project management systems. OpenHuman does not auto-assign tasks, enforce deadlines, or create workflows without your input.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Intelligence Concepts
|
||||
|
||||
AlphaHuman works by translating raw conversation activity into a small number of structured concepts. These concepts allow the system to reason about communication, coordination, and trust without storing message histories.
|
||||
OpenHuman works by translating raw conversation activity into a small number of structured concepts. These concepts allow the system to reason about communication, coordination, and trust without storing message histories.
|
||||
|
||||
**Signals:** Structured interpretations extracted from conversations. A signal might represent a decision, warning, important update, or emerging theme. Signals are independent objects that can be filtered, referenced, or aggregated.
|
||||
|
||||
@@ -88,4 +88,4 @@ AlphaHuman works by translating raw conversation activity into a small number of
|
||||
|
||||
**Workflows:** Structured processes that originate from conversation, preserving the context of decisions and commitments as actionable objects.
|
||||
|
||||
These concepts allow AlphaHuman to support trust, coordination, and intelligence without becoming invasive or requiring the storage of raw conversation data.
|
||||
These concepts allow OpenHuman to support trust, coordination, and intelligence without becoming invasive or requiring the storage of raw conversation data.
|
||||
|
||||
+20
-20
@@ -4,23 +4,23 @@ icon: users
|
||||
|
||||
# Teams & Organizations
|
||||
|
||||
AlphaHuman supports team workspaces for organizations that need shared access, centralized billing, and coordinated intelligence across members.
|
||||
OpenHuman supports team workspaces for organizations that need shared access, centralized billing, and coordinated intelligence across members.
|
||||
|
||||
Teams are designed for professional environments where multiple people rely on AlphaHuman and need shared administrative control without compromising individual privacy.
|
||||
Teams are designed for professional environments where multiple people rely on OpenHuman and need shared administrative control without compromising individual privacy.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Team Workspaces
|
||||
|
||||
A team workspace is a shared environment where members access AlphaHuman under a unified account structure. Workspaces provide:
|
||||
A team workspace is a shared environment where members access OpenHuman under a unified account structure. Workspaces provide:
|
||||
|
||||
* **Centralized billing:** one subscription covers all team members, with usage tracked per member
|
||||
* **Member management:** invite, remove, and manage team members from a single dashboard
|
||||
* **Shared configuration:** team-level settings and preferences that apply across the workspace
|
||||
- **Centralized billing:** one subscription covers all team members, with usage tracked per member
|
||||
- **Member management:** invite, remove, and manage team members from a single dashboard
|
||||
- **Shared configuration:** team-level settings and preferences that apply across the workspace
|
||||
|
||||
Each team has a unique identifier and can be managed independently from individual accounts. Users can belong to a team while still maintaining their personal AlphaHuman account and settings.
|
||||
Each team has a unique identifier and can be managed independently from individual accounts. Users can belong to a team while still maintaining their personal OpenHuman account and settings.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Roles and Permissions
|
||||
|
||||
@@ -30,13 +30,13 @@ Team workspaces support three roles:
|
||||
|
||||
**Billing Manager:** Access to billing, payment, and subscription management. Billing Managers can update payment methods, view invoices, and manage the team's plan without access to other administrative functions.
|
||||
|
||||
**Member:** Standard access to AlphaHuman within the team workspace. Members use the product normally and benefit from the team subscription, but cannot modify team settings or manage other members.
|
||||
**Member:** Standard access to OpenHuman within the team workspace. Members use the product normally and benefit from the team subscription, but cannot modify team settings or manage other members.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Shared Intelligence
|
||||
|
||||
In team environments, AlphaHuman can surface aggregated insights that help the organization operate more effectively.
|
||||
In team environments, OpenHuman can surface aggregated insights that help the organization operate more effectively.
|
||||
|
||||
**Community trends:** Patterns in conversation activity, topic evolution, and engagement across the team's connected sources, presented in aggregate form.
|
||||
|
||||
@@ -44,21 +44,21 @@ In team environments, AlphaHuman can surface aggregated insights that help the o
|
||||
|
||||
**Engagement insights:** Where coordination stress appears, where follow-through breaks down, and where attention is most needed.
|
||||
|
||||
All shared intelligence is derived from aggregated and anonymized signals. AlphaHuman does not give team administrators the ability to read private messages or monitor individual behavior. Each user's personal context remains separate, even within a team workspace.
|
||||
All shared intelligence is derived from aggregated and anonymized signals. OpenHuman does not give team administrators the ability to read private messages or monitor individual behavior. Each user's personal context remains separate, even within a team workspace.
|
||||
|
||||
{% hint style="info" %}
|
||||
**Privacy is preserved in teams.** Shared intelligence is always aggregated. Individual message content and personal analysis remain private to each user.
|
||||
{% endhint %}
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Referral Program
|
||||
|
||||
AlphaHuman offers a referral system where existing users can invite others and earn credits.
|
||||
OpenHuman offers a referral system where existing users can invite others and earn credits.
|
||||
|
||||
* Generate a personal invite code from your account settings
|
||||
* Share the code with colleagues or collaborators
|
||||
* Both the referrer and the new user receive credits when the invitation is accepted
|
||||
* Additional credit bonuses may apply when referred users subscribe to a paid plan
|
||||
- Generate a personal invite code from your account settings
|
||||
- Share the code with colleagues or collaborators
|
||||
- Both the referrer and the new user receive credits when the invitation is accepted
|
||||
- Additional credit bonuses may apply when referred users subscribe to a paid plan
|
||||
|
||||
Referral credits can be used toward AlphaHuman usage across any plan tier.
|
||||
Referral credits can be used toward OpenHuman usage across any plan tier.
|
||||
|
||||
+60
-60
@@ -6,130 +6,130 @@ icon: question
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
#### What is AlphaHuman?
|
||||
#### What is OpenHuman?
|
||||
|
||||
AlphaHuman is a personal AI assistant that connects to your communication platforms and productivity tools. It helps you manage high-volume conversations by summarizing, extracting signals, suggesting responses, and creating structured workflows all from a native app that runs on your device.
|
||||
OpenHuman is a personal AI assistant that connects to your communication platforms and productivity tools. It helps you manage high-volume conversations by summarizing, extracting signals, suggesting responses, and creating structured workflows all from a native app that runs on your device.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### What is Neocortex
|
||||
|
||||
Neocortex is AlphaHuman's memory engine. It is a human-like AI memory system that can work with over 1 billion tokens of data. It indexes 10 million tokens in under 10 seconds, costs $1 to index 5 million tokens, and runs on a MacBook Air CPU with no GPU required. Unlike vector databases, Neocortex understands time, entities, and relationships. It builds knowledge graphs and manages memory through tiered compression inspired by how the human brain works. Learn more in Neocortex.
|
||||
Neocortex is OpenHuman's memory engine. It is a human-like AI memory system that can work with over 1 billion tokens of data. It indexes 10 million tokens in under 10 seconds, costs $1 to index 5 million tokens, and runs on a MacBook Air CPU with no GPU required. Unlike vector databases, Neocortex understands time, entities, and relationships. It builds knowledge graphs and manages memory through tiered compression inspired by how the human brain works. Learn more in Neocortex.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### What does "Big Data AI" mean?
|
||||
|
||||
Every AI model today is a prompt engine. You type something, it responds, and the context disappears. AlphaHuman is different. It compresses your entire organizational life, messages, documents, tools, transactions, into a structured knowledge graph that persists and evolves. This is what we mean by Big Data AI: an AI that operates on months of your real data, not just the prompt you typed right now.
|
||||
Every AI model today is a prompt engine. You type something, it responds, and the context disappears. OpenHuman is different. It compresses your entire organizational life, messages, documents, tools, transactions, into a structured knowledge graph that persists and evolves. This is what we mean by Big Data AI: an AI that operates on months of your real data, not just the prompt you typed right now.
|
||||
|
||||
**How is AlphaHuman different from ChatGPT, Claude, or Gemini?**
|
||||
**How is OpenHuman different from ChatGPT, Claude, or Gemini?**
|
||||
|
||||
Those models are brilliant at reasoning and generation. But they are stateless. They know nothing about your actual life beyond what you paste into the chat window. AlphaHuman is the context layer that makes those models useful. It compresses your organizational data into structured intelligence that any AI can reason over. Think of it this way: ChatGPT is the brain. AlphaHuman is the memory.
|
||||
Those models are brilliant at reasoning and generation. But they are stateless. They know nothing about your actual life beyond what you paste into the chat window. OpenHuman is the context layer that makes those models useful. It compresses your organizational data into structured intelligence that any AI can reason over. Think of it this way: ChatGPT is the brain. OpenHuman is the memory.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
**How is AlphaHuman different from other AI memory solutions like Mem0, SuperMemory, or MemGPT?**
|
||||
**How is OpenHuman different from other AI memory solutions like Mem0, SuperMemory, or MemGPT?**
|
||||
|
||||
Most AI memory solutions use vector databases that retrieve whatever is semantically similar, but similarity alone says nothing about importance. They also cannot support consciousness-like systems or process data accurately at scale beyond 10 million tokens. Neocortex is architecturally different: it uses tiered memory, knowledge graphs, temporal weighting, and semantic deduplication. It processes 10 million tokens in under 10 seconds and supports over 1 billion tokens total. It does this with zero LLM dependency.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
**Is AlphaHuman open source?**
|
||||
**Is OpenHuman open source?**
|
||||
|
||||
Yes. AlphaHuman is built on the OpenClaw architecture and licensed under GNU GPL3. The full codebase is available on [GitHub](https://github.com/tinyhumansai/alphahuman). Neocortex benchmarks are also open-sourced. Contributions and feedback are welcomed.
|
||||
Yes. OpenHuman is built on the OpenClaw architecture and licensed under GNU GPL3. The full codebase is available on [GitHub](https://github.com/tinyhumansai/openhuman). Neocortex benchmarks are also open-sourced. Contributions and feedback are welcomed.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
**Is AlphaHuman AGI?**
|
||||
**Is OpenHuman AGI?**
|
||||
|
||||
No. AlphaHuman is not AGI, and we do not claim it is. It is a meaningful architectural step closer to AGI, with innovations in memory (Neocortex) and consciousness-like processing (the subconscious system) that go beyond what existing agentic systems offer. But it operates within defined boundaries and requires human judgment.
|
||||
No. OpenHuman is not AGI, and we do not claim it is. It is a meaningful architectural step closer to AGI, with innovations in memory (Neocortex) and consciousness-like processing (the subconscious system) that go beyond what existing agentic systems offer. But it operates within defined boundaries and requires human judgment.
|
||||
|
||||
#### Does AlphaHuman read all my messages?
|
||||
#### Does OpenHuman read all my messages?
|
||||
|
||||
No. AlphaHuman only processes messages **when you ask it to** and only within the scope of your request.
|
||||
No. OpenHuman only processes messages **when you ask it to** and only within the scope of your request.
|
||||
|
||||
If you ask it to summarize a specific conversation, it reads that conversation. If you do not reference a source, it is not accessed. There is no background monitoring or continuous scanning.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Is my data safe?
|
||||
|
||||
Yes. AlphaHuman is designed around zero retention of message content. Data is processed to produce an output and then discarded. Your conversations are never stored long-term, and they are never used to train AI models.
|
||||
Yes. OpenHuman is designed around zero retention of message content. Data is processed to produce an output and then discarded. Your conversations are never stored long-term, and they are never used to train AI models.
|
||||
|
||||
On desktop platforms, credentials are stored in your operating system's secure keychain. All communication between the app and AlphaHuman's servers is encrypted.
|
||||
On desktop platforms, credentials are stored in your operating system's secure keychain. All communication between the app and OpenHuman's servers is encrypted.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Does AlphaHuman store my messages?
|
||||
#### Does OpenHuman store my messages?
|
||||
|
||||
Messages are processed only to fulfill your request. They are **not permanently stored or reused** beyond producing the requested output. Derived intelligence like summaries and workflow records may persist, but raw message content does not.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Can AlphaHuman send messages on my behalf?
|
||||
#### Can OpenHuman send messages on my behalf?
|
||||
|
||||
No. AlphaHuman does not auto-send messages, post in your groups, or act on your behalf inside any connected platform. If a reply is suggested, you choose whether to use it.
|
||||
No. OpenHuman does not auto-send messages, post in your groups, or act on your behalf inside any connected platform. If a reply is suggested, you choose whether to use it.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Who is AlphaHuman for?
|
||||
#### Who is OpenHuman for?
|
||||
|
||||
AlphaHuman is useful for anyone who:
|
||||
OpenHuman is useful for anyone who:
|
||||
|
||||
* Manages high-volume communication across multiple platforms and groups
|
||||
* Needs to stay on top of decisions, action items, and context without reading everything
|
||||
* Works in distributed teams, communities, or coordination-heavy environments
|
||||
* Wants structured outputs from conversations, exportable to tools like Notion or Google Sheets
|
||||
- Manages high-volume communication across multiple platforms and groups
|
||||
- Needs to stay on top of decisions, action items, and context without reading everything
|
||||
- Works in distributed teams, communities, or coordination-heavy environments
|
||||
- Wants structured outputs from conversations, exportable to tools like Notion or Google Sheets
|
||||
|
||||
You do not need to be technical to use it.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### What platforms does AlphaHuman support?
|
||||
#### What platforms does OpenHuman support?
|
||||
|
||||
AlphaHuman runs natively on **macOS, Windows, Linux, Android, and iOS**, with a **web version** for browser access. Your account and settings sync across all platforms.
|
||||
OpenHuman runs natively on **macOS, Windows, Linux, Android, and iOS**, with a **web version** for browser access. Your account and settings sync across all platforms.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### What integrations are available?
|
||||
|
||||
AlphaHuman currently integrates with **Telegram** (read and analyze conversations), **Notion** (export structured outputs), and **Google Sheets** (export tabular data and reports). More integrations are planned.
|
||||
OpenHuman currently integrates with **Telegram** (read and analyze conversations), **Notion** (export structured outputs), and **Google Sheets** (export tabular data and reports). More integrations are planned.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### How much does AlphaHuman cost?
|
||||
#### How much does OpenHuman cost?
|
||||
|
||||
AlphaHuman offers individual and team plans with core analysis included. Deeper features are available in higher tiers. A credit system provides usage-metered flexibility, and credits can be earned through referrals.
|
||||
OpenHuman offers individual and team plans with core analysis included. Deeper features are available in higher tiers. A credit system provides usage-metered flexibility, and credits can be earned through referrals.
|
||||
|
||||
See [Pricing](../product/pricing.md) for details.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
#### Summaries feel incomplete or too broad
|
||||
|
||||
If a summary feels incomplete, the most common cause is overly broad scope. When a request spans many conversations, long time ranges, or high-volume groups, AlphaHuman prioritizes signal over detail.
|
||||
If a summary feels incomplete, the most common cause is overly broad scope. When a request spans many conversations, long time ranges, or high-volume groups, OpenHuman prioritizes signal over detail.
|
||||
|
||||
**Solution:** Narrow the request to a specific conversation, time window, or intent. AlphaHuman performs best when it knows what kind of outcome you are looking for.
|
||||
**Solution:** Narrow the request to a specific conversation, time window, or intent. OpenHuman performs best when it knows what kind of outcome you are looking for.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Important context seems missing
|
||||
|
||||
AlphaHuman only processes the data required to fulfill a request. If relevant context exists outside the scope of that request, it will not be included.
|
||||
OpenHuman only processes the data required to fulfill a request. If relevant context exists outside the scope of that request, it will not be included.
|
||||
|
||||
**Solution:** Expand the scope explicitly by referencing additional conversations or extending the time range.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Outputs feel incorrect or misinterpreted
|
||||
|
||||
AlphaHuman interprets conversations probabilistically. Tone, sarcasm, and informal language can be misread, especially in fast-moving or meme-heavy discussions.
|
||||
OpenHuman interprets conversations probabilistically. Tone, sarcasm, and informal language can be misread, especially in fast-moving or meme-heavy discussions.
|
||||
|
||||
**Solution:** Refine the request or re-run analysis with a narrower scope. Outputs should be treated as assistance rather than ground truth.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Trust or risk signals feel inaccurate
|
||||
|
||||
@@ -137,23 +137,23 @@ Trust and risk intelligence is indicative, not authoritative. Signals may lag re
|
||||
|
||||
**Solution:** Use these signals as inputs into your judgment rather than standalone decisions. Over time, as more outcomes accumulate within the same context, signal quality improves.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### A source does not appear in analysis
|
||||
|
||||
AlphaHuman can only analyze sources you have connected and that fall within the scope of your request.
|
||||
OpenHuman can only analyze sources you have connected and that fall within the scope of your request.
|
||||
|
||||
**Solution:** Ensure the source is connected in your settings and explicitly referenced or selected in your request. AlphaHuman does not automatically include all connected sources by default.
|
||||
**Solution:** Ensure the source is connected in your settings and explicitly referenced or selected in your request. OpenHuman does not automatically include all connected sources by default.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Integrations do not update as expected
|
||||
|
||||
Integrations only run when explicitly triggered by your action. AlphaHuman does not continuously sync or poll external tools.
|
||||
Integrations only run when explicitly triggered by your action. OpenHuman does not continuously sync or poll external tools.
|
||||
|
||||
**Solution:** If an export fails, check that the integration is still connected and that permissions are valid. Retrying the action after resolving any permission or availability issues usually succeeds.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Performance feels slow
|
||||
|
||||
@@ -161,18 +161,18 @@ Response time depends on request complexity, data volume, and current system loa
|
||||
|
||||
**Solution:** Large scopes and long histories require more processing. Narrowing scope and intent improves responsiveness. During early rollout phases, performance may vary as capacity is tuned.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### Revoking access and residual data
|
||||
|
||||
When access to a source or integration is revoked, AlphaHuman immediately stops processing data from that source.
|
||||
When access to a source or integration is revoked, OpenHuman immediately stops processing data from that source.
|
||||
|
||||
Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written. AlphaHuman does not retain message content after revocation.
|
||||
Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written. OpenHuman does not retain message content after revocation.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
#### When to contact support
|
||||
|
||||
If an issue persists after refining scope, checking permissions, and retrying the request, support may be required.
|
||||
|
||||
Support is intended for system-level issues, not for disputing interpretations or outcomes. AlphaHuman does not adjudicate trust or risk disagreements.
|
||||
Support is intended for system-level issues, not for disputing interpretations or outcomes. OpenHuman does not adjudicate trust or risk disagreements.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Architecture
|
||||
|
||||
AlphaHuman is built on the OpenClaw architecture and open-sourced under the GNU GPL3 license. This page explains how the major components connect.
|
||||
OpenHuman is built on the OpenClaw architecture and open-sourced under the GNU GPL3 license. This page explains how the major components connect.
|
||||
|
||||
#### The three pillars
|
||||
|
||||
AlphaHuman's architecture rests on three pillars that work together:
|
||||
OpenHuman's architecture rests on three pillars that work together:
|
||||
|
||||
<figure><img src="../.gitbook/assets/V15 — Three Pillars@2x.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
@@ -27,14 +27,14 @@ AlphaHuman's architecture rests on three pillars that work together:
|
||||
|
||||
#### Model-agnostic design
|
||||
|
||||
AlphaHuman is not locked to any single AI model. The compression engine and memory layer sit on top of the AI infrastructure, not inside it. Today the system works with specific models. Tomorrow it could feed context to any model: GPT, Claude, Gemini, Llama, Mistral, or whatever comes next.
|
||||
OpenHuman is not locked to any single AI model. The compression engine and memory layer sit on top of the AI infrastructure, not inside it. Today the system works with specific models. Tomorrow it could feed context to any model: GPT, Claude, Gemini, Llama, Mistral, or whatever comes next.
|
||||
|
||||
This is a deliberate architectural choice. AI models are commoditizing. Performance is converging. The real differentiator is the context you feed the model, and AlphaHuman owns the context layer.
|
||||
This is a deliberate architectural choice. AI models are commoditizing. Performance is converging. The real differentiator is the context you feed the model, and OpenHuman owns the context layer.
|
||||
|
||||
#### Open source
|
||||
|
||||
AlphaHuman is publicly available on GitHub under the GNU GPL3 license.
|
||||
OpenHuman is publicly available on GitHub under the GNU GPL3 license.
|
||||
|
||||
**GitHub:** [github.com/tinyhumansai/alphahuman](https://github.com/tinyhumansai/alphahuman) **Neocortex benchmarks:** [github.com/tinyhumansai/neocortex/tree/main/benchmarks](https://github.com/tinyhumansai/neocortex/tree/main/benchmarks)
|
||||
**GitHub:** [github.com/tinyhumansai/openhuman](https://github.com/tinyhumansai/openhuman) **Neocortex benchmarks:** [github.com/tinyhumansai/neocortex/tree/main/benchmarks](https://github.com/tinyhumansai/neocortex/tree/main/benchmarks)
|
||||
|
||||
Contributions, feedback, and issues are welcomed. The project is in early alpha.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Neocortex
|
||||
|
||||
Neocortex is AlphaHuman's memory engine. It is a human-like AI memory system designed to work accurately with over 1 billion tokens of data while supporting the computational demands of a subconscious system.
|
||||
Neocortex is OpenHuman's memory engine. It is a human-like AI memory system designed to work accurately with over 1 billion tokens of data while supporting the computational demands of a subconscious system.
|
||||
|
||||
<figure><img src="../.gitbook/assets/V09 — Neocortex Hero@2x.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
@@ -76,7 +76,7 @@ The result: millions of tokens of organizational noise compressed into a structu
|
||||
|
||||
#### Neocortex and the subconscious
|
||||
|
||||
Neocortex serves as the foundation for AlphaHuman's subconscious, going well beyond retrieval.
|
||||
Neocortex serves as the foundation for OpenHuman's subconscious, going well beyond retrieval.
|
||||
|
||||
Good memory recall is the prerequisite for consciousness. Neocortex provides this by recalling memories ranked on three factors: time, interactions, and randomness. The randomness element is critical. It is what enables the subconscious system to make unexpected connections and surface emergent insights.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# The Subconscious
|
||||
|
||||
AlphaHuman's subconscious is what separates it from every other AI agent. Most AI systems follow the conscious mind model: they wait for instructions and execute them. They cannot think on their own. AlphaHuman can.
|
||||
OpenHuman's subconscious is what separates it from every other AI agent. Most AI systems follow the conscious mind model: they wait for instructions and execute them. They cannot think on their own. OpenHuman can.
|
||||
|
||||
#### The Purkinje cell inspiration
|
||||
|
||||
@@ -8,11 +8,11 @@ In the human brain, there is a specialized neuron called the Purkinje cell. It i
|
||||
|
||||
The human brain operates with both a conscious and subconscious mind. The conscious mind handles deliberate, focused tasks. The subconscious processes information in the background, making connections, surfacing memories, and generating the "random" thoughts that often turn out to be the most important ones. Most agentic AI systems only model the conscious mind. They are reactive. They wait for input.
|
||||
|
||||
AlphaHuman models both.
|
||||
OpenHuman models both.
|
||||
|
||||
#### How the subconscious works
|
||||
|
||||
Inspired by the Purkinje cell, AlphaHuman uses Neocortex to periodically trigger global memory recalls. Rather than targeted retrievals in response to a specific query, these are broad, semi-random sweeps across the knowledge graph, pulling up memories based on a mix of recency, relevance, and randomness.
|
||||
Inspired by the Purkinje cell, OpenHuman uses Neocortex to periodically trigger global memory recalls. Rather than targeted retrievals in response to a specific query, these are broad, semi-random sweeps across the knowledge graph, pulling up memories based on a mix of recency, relevance, and randomness.
|
||||
|
||||
These recalls feed into a self-learning loop. The subconscious processes the recalled memories, looks for patterns, contradictions, and connections, and produces one of several outputs: a proactive insight, an action recommendation, a confirmation of an existing pattern, or a new connection between previously unrelated information.
|
||||
|
||||
@@ -24,7 +24,7 @@ The subconscious does not generate generic AI outputs. It produces context-speci
|
||||
|
||||
It might surface a risk you had not noticed: two team members making contradictory commitments in separate conversations. It might connect a trend in your trading data to a discussion from three weeks ago. It might remind you of a commitment you made that is approaching its deadline, before you think to ask.
|
||||
|
||||
The outputs are proactive. You do not need to prompt AlphaHuman to get value from the subconscious. It works in the background, feeding insights into the system that are available when you interact.
|
||||
The outputs are proactive. You do not need to prompt OpenHuman to get value from the subconscious. It works in the background, feeding insights into the system that are available when you interact.
|
||||
|
||||
#### The mirror test
|
||||
|
||||
|
||||
@@ -1,71 +1,71 @@
|
||||
# Overview
|
||||
|
||||
AlphaHuman adapts to different coordination and information environments across communication platforms. While the underlying system remains the same, the way value is realized depends on how your tools and conversations are used in each context. This section outlines common use cases to help you understand where AlphaHuman fits naturally and where it may offer limited benefit.
|
||||
OpenHuman adapts to different coordination and information environments across communication platforms. While the underlying system remains the same, the way value is realized depends on how your tools and conversations are used in each context. This section outlines common use cases to help you understand where OpenHuman fits naturally and where it may offer limited benefit.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Individual Power Users
|
||||
|
||||
Individual power users often participate in many active conversations and channels at once. Important messages are easily missed, and catching up becomes time-consuming and mentally draining.
|
||||
|
||||
In this context, AlphaHuman is used to summarize conversations, surface high-signal updates, and provide quick context before responding. Users rely on it to understand what changed, what requires attention, and where follow-ups may be needed without scrolling through entire threads.
|
||||
In this context, OpenHuman is used to summarize conversations, surface high-signal updates, and provide quick context before responding. Users rely on it to understand what changed, what requires attention, and where follow-ups may be needed without scrolling through entire threads.
|
||||
|
||||
The value here is personal clarity and reduced cognitive load rather than shared coordination.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Traders and Analysts
|
||||
|
||||
Traders and analysts use communication platforms as real-time information sources. Signal quality varies widely, and misinformation, repetition, and scams are common.
|
||||
|
||||
AlphaHuman is used to extract claims, track how information resolves over time, and surface signals weighted by historical reliability within context. Risk intelligence helps flag suspicious behavior or repeated failure patterns across groups and channels.
|
||||
OpenHuman is used to extract claims, track how information resolves over time, and surface signals weighted by historical reliability within context. Risk intelligence helps flag suspicious behavior or repeated failure patterns across groups and channels.
|
||||
|
||||
The outcome is better information filtering and reduced exposure to low-quality or malicious signals not automated trading or execution.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## DAO and Web3 Communities
|
||||
|
||||
DAOs and Web3 communities rely heavily on messaging platforms for governance discussions, coordination, and informal decision-making. As these communities grow, accountability and memory become difficult to maintain.
|
||||
|
||||
AlphaHuman is used to preserve decisions, track contributions, and support shared workflows without forcing discussions into external tools prematurely. Community-level intelligence helps moderators and operators understand participation patterns and emerging issues.
|
||||
OpenHuman is used to preserve decisions, track contributions, and support shared workflows without forcing discussions into external tools prematurely. Community-level intelligence helps moderators and operators understand participation patterns and emerging issues.
|
||||
|
||||
The value lies in maintaining continuity and accountability without sacrificing the speed and openness of chat-based coordination.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Community Managers and Moderators
|
||||
|
||||
Community managers and moderators face increasing load as groups scale. Monitoring sentiment, identifying emerging risks, and enforcing consistent standards become harder over time.
|
||||
|
||||
AlphaHuman supports these roles by surfacing aggregated insights about group health, contribution patterns, and potential risk signals. It helps moderators focus attention where it matters rather than reacting to volume alone.
|
||||
OpenHuman supports these roles by surfacing aggregated insights about group health, contribution patterns, and potential risk signals. It helps moderators focus attention where it matters rather than reacting to volume alone.
|
||||
|
||||
AlphaHuman does not replace moderation judgment or enforcement tools. It provides context and early warning signals.
|
||||
OpenHuman does not replace moderation judgment or enforcement tools. It provides context and early warning signals.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Distributed Teams
|
||||
|
||||
Distributed teams often use messaging platforms for fast coordination, even when formal work happens elsewhere. Decisions and commitments are made in chat and later forgotten or misinterpreted.
|
||||
|
||||
AlphaHuman is used to extract actions, preserve decision context, and sync structured outcomes to tools like Notion or Google Sheets when needed. This reduces friction between discussion and execution without forcing teams to abandon their preferred communication platforms.
|
||||
OpenHuman is used to extract actions, preserve decision context, and sync structured outcomes to tools like Notion or Google Sheets when needed. This reduces friction between discussion and execution without forcing teams to abandon their preferred communication platforms.
|
||||
|
||||
The benefit is improved follow-through and clarity without heavy process overhead.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## Service Providers and Contributors
|
||||
|
||||
Service providers, consultants, and contributors often operate across multiple communities and projects. Building and maintaining reputation is difficult when history is fragmented across conversations and platforms.
|
||||
|
||||
AlphaHuman helps surface contribution patterns and trust artifacts that reflect consistent behavior over time. This supports safer collaboration and discovery without requiring centralized profiles or public self-promotion.
|
||||
OpenHuman helps surface contribution patterns and trust artifacts that reflect consistent behavior over time. This supports safer collaboration and discovery without requiring centralized profiles or public self-promotion.
|
||||
|
||||
The value is portable credibility grounded in behavior rather than claims.
|
||||
|
||||
***
|
||||
---
|
||||
|
||||
## When AlphaHuman Is Not a Good Fit
|
||||
## When OpenHuman Is Not a Good Fit
|
||||
|
||||
AlphaHuman provides limited value in environments where conversations are purely social, meme-driven, or intentionally ephemeral. It is also not designed for high-frequency trading execution, formal project management, or environments that require strict real-time guarantees.
|
||||
OpenHuman provides limited value in environments where conversations are purely social, meme-driven, or intentionally ephemeral. It is also not designed for high-frequency trading execution, formal project management, or environments that require strict real-time guarantees.
|
||||
|
||||
Understanding these boundaries helps users apply AlphaHuman where it is strongest.
|
||||
Understanding these boundaries helps users apply OpenHuman where it is strongest.
|
||||
|
||||
+12
-10
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openhuman",
|
||||
"version": "0.49.0",
|
||||
"version": "0.49.15",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -11,20 +11,22 @@
|
||||
"compile": "tsc --noEmit",
|
||||
"preview": "vite preview",
|
||||
"tauri": "tauri",
|
||||
"macos:build:intel": "source scripts/load-dotenv.sh && tauri build --bundles app dmg --target x86_64-apple-darwin",
|
||||
"tauri:build:ui": "tauri build -- --bin OpenHuman",
|
||||
"macos:build:intel": "source scripts/load-dotenv.sh && tauri build --bundles app dmg --target x86_64-apple-darwin -- --bin OpenHuman",
|
||||
"macos:build:intel:debug": "yarn macos:build:intel --debug",
|
||||
"macos:build:debug": "yarn macos:build:release --debug",
|
||||
"macos:build:release": "source scripts/load-dotenv.sh && tauri build --bundles app dmg",
|
||||
"macos:build:sign:release": "source scripts/load-env.sh && tauri build --bundles app dmg",
|
||||
"macos:build:release": "source scripts/load-dotenv.sh && tauri build --bundles app dmg -- --bin OpenHuman",
|
||||
"macos:build:release:signed": "source scripts/load-env.sh && tauri build --bundles app dmg -- --bin OpenHuman",
|
||||
"macos:build:sign:release": "yarn macos:build:release:signed",
|
||||
"macos:run": "open 'src-tauri/target/debug/bundle/macos/OpenHuman.app'",
|
||||
"macos:dev": "yarn macos:build:debug && open 'src-tauri/target/debug/bundle/macos/OpenHuman.app'",
|
||||
"android:dev": "tauri android dev",
|
||||
"android:build": "tauri android build",
|
||||
"test": "vitest run",
|
||||
"test:unit": "vitest run",
|
||||
"test:unit:watch": "vitest",
|
||||
"test:watch": "vitest",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"test": "vitest run --config test/vitest.config.ts",
|
||||
"test:unit": "vitest run --config test/vitest.config.ts",
|
||||
"test:unit:watch": "vitest --config test/vitest.config.ts",
|
||||
"test:watch": "vitest --config test/vitest.config.ts",
|
||||
"test:coverage": "vitest run --config test/vitest.config.ts --coverage",
|
||||
"test:rust": "source $HOME/.cargo/env 2>/dev/null; cargo test --manifest-path src-tauri/Cargo.toml",
|
||||
"test:e2e:build": "bash scripts/e2e-build.sh",
|
||||
"test:e2e:login": "bash scripts/e2e-login.sh",
|
||||
@@ -78,7 +80,7 @@
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@tailwindcss/forms": "^0.5.11",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@tauri-apps/cli": "2.9.6",
|
||||
"@tauri-apps/cli": "2.10.0",
|
||||
"@testing-library/dom": "^10.4.1",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"before": "0000000000000000000000000000000000000000",
|
||||
"after": "19281e16457e7c8ff8e6bda6ceda77f0880d10d2",
|
||||
"repository": {
|
||||
"full_name": "vezuresdotxyz/alphahuman-frontend-runner",
|
||||
"full_name": "vezuresdotxyz/openhuman-frontend-runner",
|
||||
"default_branch": "main",
|
||||
"name": "alphahuman-frontend-runner",
|
||||
"name": "openhuman-frontend-runner",
|
||||
"owner": { "login": "vezuresdotxyz" }
|
||||
},
|
||||
"head_commit": {
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
{
|
||||
"secrets": {
|
||||
"XGH_TOKEN": "",
|
||||
"GITHUB_TOKEN": "",
|
||||
"UPDATER_GIST_URL": "",
|
||||
"UPDATER_GIST_ID": "",
|
||||
"UPDATER_PUBLIC_KEY": "",
|
||||
"UPDATER_PRIVATE_KEY": "",
|
||||
"UPDATER_PRIVATE_KEY_PASSWORD": "",
|
||||
"APPLE_CERTIFICATE_BASE64": "",
|
||||
"APPLE_CERTIFICATE_PASSWORD": "",
|
||||
"APPLE_SIGNING_IDENTITY": "",
|
||||
"APPLE_ID": "",
|
||||
"APPLE_APP_SPECIFIC_PASSWORD": "",
|
||||
"APPLE_PASSWORD": "",
|
||||
"APPLE_SIGNING_IDENTITY": "",
|
||||
"APPLE_TEAM_ID": "",
|
||||
"VITE_TELEGRAM_BOT_USERNAME": "",
|
||||
"VITE_TELEGRAM_BOT_ID": "",
|
||||
"VITE_SENTRY_DSN": ""
|
||||
"GITHUB_TOKEN": "",
|
||||
"TAURI_SIGNING_PRIVATE_KEY_PASSWORD": "",
|
||||
"TAURI_SIGNING_PRIVATE_KEY": "",
|
||||
"XGH_TOKEN": "",
|
||||
"XGITHUB_APP_ID": "",
|
||||
"XGITHUB_APP_PRIVATE_KEY": ""
|
||||
},
|
||||
"vars": {
|
||||
"BASE_URL": "https://localhost",
|
||||
"VITE_BACKEND_URL": "https://localhost:5005",
|
||||
"VITE_SKILLS_GITHUB_REPO": "",
|
||||
"VITE_SENTRY_DSN": "",
|
||||
"VITE_DEBUG": "true"
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}"
|
||||
# Clean cached app data for a fresh state — Redux Persist would otherwise
|
||||
# remember the JWT from a previous run and skip the login flow.
|
||||
echo "Cleaning cached app data..."
|
||||
rm -rf ~/Library/WebKit/com.alphahuman.app
|
||||
rm -rf ~/Library/Caches/com.alphahuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.alphahuman.app"
|
||||
rm -rf ~/Library/WebKit/com.openhuman.app
|
||||
rm -rf ~/Library/Caches/com.openhuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.openhuman.app"
|
||||
|
||||
# Verify the frontend dist has the mock server URL baked in.
|
||||
DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)"
|
||||
|
||||
@@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}"
|
||||
# Clean cached app data for a fresh state — Redux Persist would otherwise
|
||||
# remember the JWT from a previous run and skip the login flow.
|
||||
echo "Cleaning cached app data..."
|
||||
rm -rf ~/Library/WebKit/com.alphahuman.app
|
||||
rm -rf ~/Library/Caches/com.alphahuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.alphahuman.app"
|
||||
rm -rf ~/Library/WebKit/com.openhuman.app
|
||||
rm -rf ~/Library/Caches/com.openhuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.openhuman.app"
|
||||
|
||||
# Verify the frontend dist has the mock server URL baked in.
|
||||
DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)"
|
||||
|
||||
@@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}"
|
||||
# Clean cached app data for a fresh state — Redux Persist would otherwise
|
||||
# remember the JWT from a previous run and skip the login flow.
|
||||
echo "Cleaning cached app data..."
|
||||
rm -rf ~/Library/WebKit/com.alphahuman.app
|
||||
rm -rf ~/Library/Caches/com.alphahuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.alphahuman.app"
|
||||
rm -rf ~/Library/WebKit/com.openhuman.app
|
||||
rm -rf ~/Library/Caches/com.openhuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.openhuman.app"
|
||||
|
||||
# Verify the frontend dist has the mock server URL baked in.
|
||||
DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)"
|
||||
|
||||
@@ -24,9 +24,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}"
|
||||
# Clean cached app data for a fresh state — Redux Persist would otherwise
|
||||
# remember the JWT from a previous run and skip the login flow.
|
||||
echo "Cleaning cached app data..."
|
||||
rm -rf ~/Library/WebKit/com.alphahuman.app
|
||||
rm -rf ~/Library/Caches/com.alphahuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.alphahuman.app"
|
||||
rm -rf ~/Library/WebKit/com.openhuman.app
|
||||
rm -rf ~/Library/Caches/com.openhuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.openhuman.app"
|
||||
|
||||
# Verify the frontend dist has the mock server URL baked in (not production).
|
||||
# Tauri compresses assets when embedding, so we check dist/ not the binary.
|
||||
|
||||
@@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}"
|
||||
# Clean cached app data for a fresh state — Redux Persist would otherwise
|
||||
# remember the JWT from a previous run and skip the login flow.
|
||||
echo "Cleaning cached app data..."
|
||||
rm -rf ~/Library/WebKit/com.alphahuman.app
|
||||
rm -rf ~/Library/Caches/com.alphahuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.alphahuman.app"
|
||||
rm -rf ~/Library/WebKit/com.openhuman.app
|
||||
rm -rf ~/Library/Caches/com.openhuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.openhuman.app"
|
||||
|
||||
# Verify the frontend dist has the mock server URL baked in.
|
||||
DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)"
|
||||
|
||||
@@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}"
|
||||
# Clean cached app data for a fresh state — Redux Persist would otherwise
|
||||
# remember the JWT from a previous run and skip the login flow.
|
||||
echo "Cleaning cached app data..."
|
||||
rm -rf ~/Library/WebKit/com.alphahuman.app
|
||||
rm -rf ~/Library/Caches/com.alphahuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.alphahuman.app"
|
||||
rm -rf ~/Library/WebKit/com.openhuman.app
|
||||
rm -rf ~/Library/Caches/com.openhuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.openhuman.app"
|
||||
|
||||
# Verify the frontend dist has the mock server URL baked in.
|
||||
DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)"
|
||||
|
||||
@@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}"
|
||||
# Clean cached app data for a fresh state — Redux Persist would otherwise
|
||||
# remember the JWT from a previous run and skip the login flow.
|
||||
echo "Cleaning cached app data..."
|
||||
rm -rf ~/Library/WebKit/com.alphahuman.app
|
||||
rm -rf ~/Library/Caches/com.alphahuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.alphahuman.app"
|
||||
rm -rf ~/Library/WebKit/com.openhuman.app
|
||||
rm -rf ~/Library/Caches/com.openhuman.app
|
||||
rm -rf "$HOME/Library/Application Support/com.openhuman.app"
|
||||
|
||||
# Verify the frontend dist has the mock server URL baked in.
|
||||
DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)"
|
||||
|
||||
@@ -8,7 +8,7 @@ export default function prepareTauriConfig() {
|
||||
const config = {
|
||||
build: { frontendDist, devUrl: null },
|
||||
bundle: { windows: {} },
|
||||
identifier: 'com.alphahuman.app',
|
||||
identifier: 'com.openhuman.app',
|
||||
};
|
||||
|
||||
if (process.env.WITH_UPDATER === 'true') {
|
||||
|
||||
Executable
+143
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run the standalone macOS ARM64 Tauri build via nektos/act (self-hosted = your Mac).
|
||||
# No prepare-release, no tagging, no GitHub release upload (includeUpdaterJson: false).
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/run-macos-arm64-build.sh # dry-run
|
||||
# ./scripts/run-macos-arm64-build.sh --run # full signed build on this machine
|
||||
#
|
||||
# Requires: act, jq, scripts/ci-secrets.json (copy from ci-secrets.example.json)
|
||||
|
||||
set -euo pipefail
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
WORKFLOW=".github/workflows/macos-arm64-build.yml"
|
||||
SECRETS_JSON="scripts/ci-secrets.json"
|
||||
RUN_MODE="dryrun"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--run)
|
||||
RUN_MODE="run"
|
||||
shift
|
||||
;;
|
||||
--dryrun|-n)
|
||||
RUN_MODE="dryrun"
|
||||
shift
|
||||
;;
|
||||
--secrets-json)
|
||||
SECRETS_JSON="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ! -f "$SECRETS_JSON" ]]; then
|
||||
echo "Secrets JSON not found: $SECRETS_JSON" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v act >/dev/null 2>&1; then
|
||||
echo "act is required. Install with: brew install act" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "jq is required. Install with: brew install jq" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SECRETS_FILE="$(mktemp)"
|
||||
VARS_FILE="$(mktemp)"
|
||||
EVENT_JSON="$(mktemp)"
|
||||
MERGED_SECRETS="$(mktemp)"
|
||||
trap 'rm -f "$SECRETS_FILE" "$VARS_FILE" "$EVENT_JSON" "$MERGED_SECRETS"' EXIT
|
||||
|
||||
jq '
|
||||
.secrets |= (
|
||||
. + {
|
||||
APPLE_APP_SPECIFIC_PASSWORD: (
|
||||
if (.APPLE_APP_SPECIFIC_PASSWORD // "") | length > 0 then .APPLE_APP_SPECIFIC_PASSWORD
|
||||
else (.APPLE_PASSWORD // "") end
|
||||
)
|
||||
}
|
||||
)
|
||||
' "$SECRETS_JSON" > "$MERGED_SECRETS"
|
||||
|
||||
jq -r '
|
||||
def dotenv_escape:
|
||||
gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n");
|
||||
(.secrets // {}) | to_entries[] | select(.key != "GITHUB_TOKEN") | "\(.key)=\"\(.value | dotenv_escape)\""
|
||||
' "$MERGED_SECRETS" > "$SECRETS_FILE"
|
||||
jq -r '
|
||||
def dotenv_escape:
|
||||
gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n");
|
||||
(.vars // {}) | to_entries[] | "\(.key)=\"\(.value | dotenv_escape)\""
|
||||
' "$SECRETS_JSON" > "$VARS_FILE"
|
||||
|
||||
REPO_FULL="${GITHUB_REPOSITORY:-}"
|
||||
if [[ -z "$REPO_FULL" ]]; then
|
||||
REPO_FULL="$(git remote get-url origin 2>/dev/null | sed -E 's#^git@github\.com:([^/]+)/([^/.]+)(\.git)?$#\1/\2#; s#^https://github\.com/([^/]+)/([^/.]+)(\.git)?$#\1/\2#')"
|
||||
fi
|
||||
if [[ -z "$REPO_FULL" || "$REPO_FULL" != */* ]]; then
|
||||
echo "Could not resolve GitHub owner/repo (set GITHUB_REPOSITORY or fix git remote origin)" >&2
|
||||
exit 1
|
||||
fi
|
||||
OWNER="${REPO_FULL%%/*}"
|
||||
REPO_NAME="${REPO_FULL##*/}"
|
||||
|
||||
REF="$(git symbolic-ref -q HEAD || true)"
|
||||
if [[ -z "$REF" ]]; then
|
||||
REF="refs/heads/main"
|
||||
fi
|
||||
|
||||
jq -n \
|
||||
--arg ref "$REF" \
|
||||
--arg full "$REPO_FULL" \
|
||||
--arg owner "$OWNER" \
|
||||
--arg name "$REPO_NAME" \
|
||||
'{
|
||||
ref: $ref,
|
||||
inputs: {},
|
||||
repository: {
|
||||
full_name: $full,
|
||||
default_branch: "main",
|
||||
name: $name,
|
||||
owner: { login: $owner }
|
||||
},
|
||||
sender: { login: "local-dev" }
|
||||
}' > "$EVENT_JSON"
|
||||
|
||||
echo "Workflow: $WORKFLOW"
|
||||
echo "Secrets: $SECRETS_JSON"
|
||||
echo "Ref: $REF"
|
||||
echo "Mode: $RUN_MODE"
|
||||
echo
|
||||
|
||||
# act -b copies the tree without .git — submodules must be materialized here first.
|
||||
if [[ -d .git ]]; then
|
||||
echo "Syncing git submodules (required for skills/, etc.)..."
|
||||
git submodule update --init --recursive
|
||||
fi
|
||||
echo
|
||||
|
||||
ACT_ARGS=(
|
||||
workflow_dispatch
|
||||
-W "$WORKFLOW"
|
||||
--eventpath "$EVENT_JSON"
|
||||
--secret-file "$SECRETS_FILE"
|
||||
--var-file "$VARS_FILE"
|
||||
-b
|
||||
-P macos-latest=-self-hosted
|
||||
)
|
||||
|
||||
if [[ "$RUN_MODE" == "dryrun" ]]; then
|
||||
echo "Dry-run only. Use --run for the full macOS ARM64 build."
|
||||
act "${ACT_ARGS[@]}" -n
|
||||
else
|
||||
act "${ACT_ARGS[@]}"
|
||||
fi
|
||||
@@ -1,13 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
create-dmg \
|
||||
--volname "AlphaHuman installer" \
|
||||
--volname "OpenHuman installer" \
|
||||
--volicon "./src-tauri/icons/icon.icns" \
|
||||
--background "./src-tauri/images/background-dmg.svg" \
|
||||
--window-size 540 380 \
|
||||
--icon-size 100 \
|
||||
--icon "AlphaHuman.app" 138 225 \
|
||||
--hide-extension "AlphaHuman.app" \
|
||||
--icon "OpenHuman.app" 138 225 \
|
||||
--hide-extension "OpenHuman.app" \
|
||||
--app-drop-link 402 225 \
|
||||
--no-internet-enable \
|
||||
"$1" \
|
||||
|
||||
@@ -41,9 +41,9 @@ cat > "$EVENT_JSON" <<EOF
|
||||
"before": "0000000000000000000000000000000000000000",
|
||||
"after": "$CURRENT_REF",
|
||||
"repository": {
|
||||
"full_name": "vezuresdotxyz/alphahuman-frontend-runner",
|
||||
"full_name": "vezuresdotxyz/openhuman-frontend-runner",
|
||||
"default_branch": "main",
|
||||
"name": "alphahuman-frontend-runner",
|
||||
"name": "openhuman-frontend-runner",
|
||||
"owner": { "login": "vezuresdotxyz" }
|
||||
},
|
||||
"head_commit": {
|
||||
@@ -60,11 +60,19 @@ SECRETS_FILE=$(mktemp)
|
||||
VARS_FILE=$(mktemp)
|
||||
trap 'rm -f "$SECRETS_FILE" "$VARS_FILE"' EXIT
|
||||
|
||||
# Extract "secrets" object → KEY=VALUE
|
||||
jq -r '.secrets // {} | to_entries[] | "\(.key)=\(.value)"' "$SECRETS_JSON" > "$SECRETS_FILE"
|
||||
# Extract "secrets" object → KEY=VALUE (quoted/escaped for act dotenv parsing)
|
||||
jq -r '
|
||||
def dotenv_escape:
|
||||
gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n");
|
||||
(.secrets // {}) | to_entries[] | "\(.key)=\"\(.value | dotenv_escape)\""
|
||||
' "$SECRETS_JSON" > "$SECRETS_FILE"
|
||||
|
||||
# Extract "vars" object → KEY=VALUE
|
||||
jq -r '.vars // {} | to_entries[] | "\(.key)=\(.value)"' "$SECRETS_JSON" > "$VARS_FILE"
|
||||
jq -r '
|
||||
def dotenv_escape:
|
||||
gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n");
|
||||
(.vars // {}) | to_entries[] | "\(.key)=\"\(.value | dotenv_escape)\""
|
||||
' "$SECRETS_JSON" > "$VARS_FILE"
|
||||
|
||||
echo "Loaded $(wc -l < "$SECRETS_FILE" | tr -d ' ') secrets and $(wc -l < "$VARS_FILE" | tr -d ' ') vars from $SECRETS_JSON"
|
||||
|
||||
|
||||
Executable
+198
@@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env bash
|
||||
# Test the Release workflow locally using act.
|
||||
#
|
||||
# Defaults are safe:
|
||||
# - Uses scripts/ci-secrets.example.json for secrets/vars.
|
||||
# - Runs in dry-run mode unless --run is passed.
|
||||
#
|
||||
# For --run: set XGH_TOKEN in scripts/ci-secrets.json (PAT with repo scope). prepare-release uses
|
||||
# XGH_TOKEN for checkout/push. Do not put a bad GITHUB_TOKEN in ci-secrets.json — act uses it to
|
||||
# clone action repos and an invalid PAT breaks even public clones. github-script steps use
|
||||
# secrets.XGH_TOKEN (see release.yml).
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/test-release-act.sh
|
||||
# ./scripts/test-release-act.sh --run
|
||||
# ./scripts/test-release-act.sh --list
|
||||
# ./scripts/test-release-act.sh --job prepare-release
|
||||
# ./scripts/test-release-act.sh --release-type minor
|
||||
# ./scripts/test-release-act.sh --secrets-json scripts/ci-secrets.json --run
|
||||
# # Single macOS (Apple Silicon) build for signing — pass through to act --matrix:
|
||||
# ./scripts/test-release-act.sh --run --job build-artifacts \
|
||||
# --matrix 'settings.platform:macos-latest' --matrix 'settings.args:--target aarch64-apple-darwin'
|
||||
|
||||
set -euo pipefail
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
WORKFLOW=".github/workflows/release.yml"
|
||||
SECRETS_JSON="scripts/ci-secrets.json"
|
||||
RELEASE_TYPE="patch"
|
||||
RUN_MODE="dryrun"
|
||||
JOB_NAME=""
|
||||
MATRIX_ARGS=()
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--run)
|
||||
RUN_MODE="run"
|
||||
shift
|
||||
;;
|
||||
--dryrun)
|
||||
RUN_MODE="dryrun"
|
||||
shift
|
||||
;;
|
||||
--list)
|
||||
RUN_MODE="list"
|
||||
shift
|
||||
;;
|
||||
--job)
|
||||
JOB_NAME="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--release-type)
|
||||
RELEASE_TYPE="${2:-patch}"
|
||||
shift 2
|
||||
;;
|
||||
--secrets-json)
|
||||
SECRETS_JSON="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--matrix)
|
||||
MATRIX_ARGS+=(--matrix "${2:-}")
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ! -f "$SECRETS_JSON" ]]; then
|
||||
echo "Secrets JSON not found: $SECRETS_JSON" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v act >/dev/null 2>&1; then
|
||||
echo "act is required. Install with: brew install act" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "jq is required. Install with: brew install jq" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$RELEASE_TYPE" in
|
||||
major|minor|patch) ;;
|
||||
*)
|
||||
echo "--release-type must be one of: major, minor, patch" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$RUN_MODE" == "list" ]]; then
|
||||
act -W "$WORKFLOW" --list
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SECRETS_FILE="$(mktemp)"
|
||||
VARS_FILE="$(mktemp)"
|
||||
EVENT_JSON="$(mktemp)"
|
||||
MERGED_SECRETS="$(mktemp)"
|
||||
trap 'rm -f "$SECRETS_FILE" "$VARS_FILE" "$EVENT_JSON" "$MERGED_SECRETS"' EXIT
|
||||
|
||||
# Merge defaults: APPLE_APP_SPECIFIC_PASSWORD (APPLE_PASSWORD is a common alias).
|
||||
# Do not put GITHUB_TOKEN in the act secret file — an invalid PAT breaks act's clone of public actions.
|
||||
jq '
|
||||
.secrets |= (
|
||||
. + {
|
||||
APPLE_APP_SPECIFIC_PASSWORD: (
|
||||
if (.APPLE_APP_SPECIFIC_PASSWORD // "") | length > 0 then .APPLE_APP_SPECIFIC_PASSWORD
|
||||
else (.APPLE_PASSWORD // "") end
|
||||
)
|
||||
}
|
||||
)
|
||||
' "$SECRETS_JSON" > "$MERGED_SECRETS"
|
||||
|
||||
# act --secret-file/--var-file expect dotenv format. Unquoted multiline values break the
|
||||
# parser (PEM/private keys look like extra KEY= lines and trigger errors on '/' etc.).
|
||||
jq -r '
|
||||
def dotenv_escape:
|
||||
gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n");
|
||||
(.secrets // {}) | to_entries[] | select(.key != "GITHUB_TOKEN") | "\(.key)=\"\(.value | dotenv_escape)\""
|
||||
' "$MERGED_SECRETS" > "$SECRETS_FILE"
|
||||
jq -r '
|
||||
def dotenv_escape:
|
||||
gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n");
|
||||
(.vars // {}) | to_entries[] | "\(.key)=\"\(.value | dotenv_escape)\""
|
||||
' "$SECRETS_JSON" > "$VARS_FILE"
|
||||
|
||||
# Use real owner/repo from git so context.repo and tauri-action match your fork (not local/openhuman).
|
||||
REPO_FULL="${GITHUB_REPOSITORY:-}"
|
||||
if [[ -z "$REPO_FULL" ]]; then
|
||||
REPO_FULL="$(git remote get-url origin 2>/dev/null | sed -E 's#^git@github\.com:([^/]+)/([^/.]+)(\.git)?$#\1/\2#; s#^https://github\.com/([^/]+)/([^/.]+)(\.git)?$#\1/\2#')"
|
||||
fi
|
||||
if [[ -z "$REPO_FULL" || "$REPO_FULL" != */* ]]; then
|
||||
echo "Could not resolve GitHub owner/repo (set GITHUB_REPOSITORY or fix git remote origin)" >&2
|
||||
exit 1
|
||||
fi
|
||||
OWNER="${REPO_FULL%%/*}"
|
||||
REPO_NAME="${REPO_FULL##*/}"
|
||||
|
||||
jq -n \
|
||||
--arg ref "refs/heads/main" \
|
||||
--arg rt "$RELEASE_TYPE" \
|
||||
--arg full "$REPO_FULL" \
|
||||
--arg owner "$OWNER" \
|
||||
--arg name "$REPO_NAME" \
|
||||
'{
|
||||
ref: $ref,
|
||||
inputs: { release_type: $rt },
|
||||
repository: {
|
||||
full_name: $full,
|
||||
default_branch: "main",
|
||||
name: $name,
|
||||
owner: { login: $owner }
|
||||
},
|
||||
sender: { login: "local-dev" }
|
||||
}' > "$EVENT_JSON"
|
||||
|
||||
echo "Workflow: $WORKFLOW"
|
||||
echo "Secrets: $SECRETS_JSON"
|
||||
echo "Input: release_type=$RELEASE_TYPE"
|
||||
echo "Mode: $RUN_MODE"
|
||||
if [[ -n "$JOB_NAME" ]]; then
|
||||
echo "Job: $JOB_NAME"
|
||||
fi
|
||||
if [[ ${#MATRIX_ARGS[@]} -gt 0 ]]; then
|
||||
echo "Matrix: ${MATRIX_ARGS[*]}"
|
||||
fi
|
||||
echo
|
||||
|
||||
ACT_ARGS=(
|
||||
workflow_dispatch
|
||||
-W "$WORKFLOW"
|
||||
--eventpath "$EVENT_JSON"
|
||||
--secret-file "$SECRETS_FILE"
|
||||
--var-file "$VARS_FILE"
|
||||
--container-architecture linux/amd64
|
||||
-P ubuntu-latest=catthehacker/ubuntu:act-latest
|
||||
-P ubuntu-22.04=catthehacker/ubuntu:act-22.04
|
||||
-P macos-latest=-self-hosted
|
||||
)
|
||||
|
||||
if [[ -n "$JOB_NAME" ]]; then
|
||||
ACT_ARGS+=(-j "$JOB_NAME")
|
||||
fi
|
||||
|
||||
if [[ ${#MATRIX_ARGS[@]} -gt 0 ]]; then
|
||||
ACT_ARGS+=("${MATRIX_ARGS[@]}")
|
||||
fi
|
||||
|
||||
if [[ "$RUN_MODE" == "dryrun" ]]; then
|
||||
echo "Dry-run only. Use --run to execute."
|
||||
act "${ACT_ARGS[@]}" -n
|
||||
else
|
||||
act "${ACT_ARGS[@]}"
|
||||
fi
|
||||
@@ -183,7 +183,7 @@ describe('OpenClaw Formatter', () => {
|
||||
const result = generateOpenClawMarkdown(tools);
|
||||
|
||||
// Check main sections
|
||||
expect(result).toContain('# AlphaHuman Tools');
|
||||
expect(result).toContain('# OpenHuman Tools');
|
||||
expect(result).toContain('## Overview');
|
||||
expect(result).toContain('## Environment Configuration');
|
||||
expect(result).toContain('## Tool Categories');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* AlphaHuman Tools Discovery Script
|
||||
* OpenHuman Tools Discovery Script
|
||||
*
|
||||
* Discovers all available tools from the V8 skills runtime and generates
|
||||
* a comprehensive TOOLS.md file following OpenClaw framework standards.
|
||||
@@ -12,16 +12,10 @@ import { dirname, join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import { generateOpenClawMarkdown } from './openClaw-formatter.js';
|
||||
import {
|
||||
executeTauriDiscovery,
|
||||
getTauriEnvironmentInfo,
|
||||
prepareTauriEnvironment,
|
||||
validateTauriEnvironment,
|
||||
} from './tauri-integration.js';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
const AI_DIR = join(PROJECT_ROOT, 'ai');
|
||||
const AI_DIR = join(PROJECT_ROOT, 'src-tauri', 'ai');
|
||||
const TOOLS_OUTPUT = join(AI_DIR, 'TOOLS.md');
|
||||
|
||||
// Environment categories for OpenClaw compatibility
|
||||
@@ -42,39 +36,7 @@ const ENVIRONMENTS = {
|
||||
* @returns {Promise<Array>} Array of discovered tools with skill metadata
|
||||
*/
|
||||
async function discoverTools() {
|
||||
console.log('🔍 Discovering tools from V8 skills runtime...');
|
||||
|
||||
// Check if Tauri environment is available
|
||||
const tauriAvailable = await validateTauriEnvironment();
|
||||
|
||||
if (tauriAvailable) {
|
||||
try {
|
||||
console.log('🔧 Preparing Tauri environment...');
|
||||
await prepareTauriEnvironment();
|
||||
|
||||
console.log('🚀 Executing Tauri tools discovery...');
|
||||
const realTools = await executeTauriDiscovery({
|
||||
timeout: 60000, // 60 seconds
|
||||
retries: 2,
|
||||
verbose: process.env.VERBOSE === 'true',
|
||||
});
|
||||
|
||||
if (realTools && realTools.length > 0) {
|
||||
console.log(
|
||||
`✅ Discovered ${realTools.length} tools from ${new Set(realTools.map(t => t.skillId)).size} skills via Tauri`
|
||||
);
|
||||
return realTools;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Could not discover tools from Tauri runtime:', error.message);
|
||||
console.log('📋 Using development mock data instead');
|
||||
}
|
||||
} else {
|
||||
console.warn('⚠️ Tauri environment not available');
|
||||
console.log('📋 Using development mock data instead');
|
||||
}
|
||||
|
||||
// Fallback to mock data for development
|
||||
console.log('🔍 Discovering tools from mock registry...');
|
||||
const mockTools = generateMockToolsForDevelopment();
|
||||
console.log(
|
||||
`✅ Using mock data: ${mockTools.length} tools from ${new Set(mockTools.map(t => t.skillId)).size} skills`
|
||||
@@ -160,7 +122,7 @@ function generateMockToolsForDevelopment() {
|
||||
*/
|
||||
async function main() {
|
||||
try {
|
||||
console.log('🚀 Starting AlphaHuman tools discovery...');
|
||||
console.log('🚀 Starting OpenHuman tools discovery...');
|
||||
|
||||
// Discover all available tools
|
||||
const tools = await discoverTools();
|
||||
@@ -195,75 +157,9 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to discover tools from a running Tauri process
|
||||
* @returns {Promise<Array>} Array of tools from Tauri runtime
|
||||
*/
|
||||
async function discoverToolsFromTauri() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Try to spawn a minimal Tauri process for tool discovery
|
||||
const isWindows = process.platform === 'win32';
|
||||
const tauriCommand = isWindows ? 'cargo.exe' : 'cargo';
|
||||
|
||||
const args = [
|
||||
'run',
|
||||
'--manifest-path',
|
||||
join(PROJECT_ROOT, 'src-tauri', 'Cargo.toml'),
|
||||
'--bin',
|
||||
'alphahuman-tools-discovery',
|
||||
];
|
||||
|
||||
console.log('🔧 Attempting to run tools discovery via Cargo...');
|
||||
|
||||
const child = spawn(tauriCommand, args, {
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
cwd: PROJECT_ROOT,
|
||||
env: { ...process.env, TAURI_TOOLS_DISCOVERY: 'true' },
|
||||
});
|
||||
|
||||
let output = '';
|
||||
let errorOutput = '';
|
||||
|
||||
child.stdout.on('data', data => {
|
||||
output += data.toString();
|
||||
});
|
||||
|
||||
child.stderr.on('data', data => {
|
||||
errorOutput += data.toString();
|
||||
});
|
||||
|
||||
child.on('close', code => {
|
||||
if (code === 0 && output.trim()) {
|
||||
try {
|
||||
const result = JSON.parse(output.trim());
|
||||
if (result.success && result.tools) {
|
||||
resolve(result.tools);
|
||||
} else {
|
||||
reject(new Error(result.error || 'Unknown error from Tauri'));
|
||||
}
|
||||
} catch (parseError) {
|
||||
reject(new Error(`Failed to parse Tauri output: ${parseError.message}`));
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`Tauri process failed (code ${code}): ${errorOutput}`));
|
||||
}
|
||||
});
|
||||
|
||||
child.on('error', error => {
|
||||
reject(new Error(`Failed to spawn Tauri process: ${error.message}`));
|
||||
});
|
||||
|
||||
// Timeout after 30 seconds
|
||||
setTimeout(() => {
|
||||
child.kill();
|
||||
reject(new Error('Tauri discovery process timed out'));
|
||||
}, 30000);
|
||||
});
|
||||
}
|
||||
|
||||
// Run if called directly
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
main();
|
||||
}
|
||||
|
||||
export { discoverTools, discoverToolsFromTauri, generateMockToolsForDevelopment };
|
||||
export { discoverTools, generateMockToolsForDevelopment };
|
||||
|
||||
@@ -78,7 +78,7 @@ export const TOOL_CATEGORIES = {
|
||||
* @returns {string} Formatted markdown for parameters
|
||||
*/
|
||||
export function formatParameters(schema) {
|
||||
if (!schema || !schema.properties) {
|
||||
if (!schema || !schema.properties || Object.keys(schema.properties).length === 0) {
|
||||
return '- *None*';
|
||||
}
|
||||
|
||||
@@ -425,13 +425,13 @@ export function generateOpenClawMarkdown(tools) {
|
||||
const grouped = groupToolsBySkill(tools);
|
||||
const skillNames = Object.keys(grouped);
|
||||
|
||||
let content = `# AlphaHuman Tools
|
||||
let content = `# OpenHuman Tools
|
||||
|
||||
This document lists all available tools that AlphaHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated during build time.
|
||||
This document lists all available tools that OpenHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated during build time.
|
||||
|
||||
## Overview
|
||||
|
||||
AlphaHuman has access to **${tools.length} tools** across **${skillNames.length} integrations** organized into **${Object.keys(TOOL_CATEGORIES).length} categories**.
|
||||
OpenHuman has access to **${tools.length} tools** across **${skillNames.length} integrations** organized into **${Object.keys(TOOL_CATEGORIES).length} categories**.
|
||||
|
||||
**Quick Statistics:**
|
||||
${skillNames.map(skill => `- **${grouped[skill].name}**: ${grouped[skill].tools.length} tools`).join('\n')}
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Tauri Integration for Tools Discovery
|
||||
*
|
||||
* Provides integration utilities for discovering tools via Tauri runtime.
|
||||
* Handles cross-platform execution, error handling, and fallbacks.
|
||||
*/
|
||||
import { spawn } from 'child_process';
|
||||
import { join } from 'path';
|
||||
import { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
|
||||
/**
|
||||
* Platform-specific command detection
|
||||
* @returns {Object} Command and arguments for spawning Tauri process
|
||||
*/
|
||||
export function getTauriCommand() {
|
||||
const isWindows = process.platform === 'win32';
|
||||
|
||||
return {
|
||||
command: isWindows ? 'cargo.exe' : 'cargo',
|
||||
args: [
|
||||
'run',
|
||||
'--manifest-path',
|
||||
join(PROJECT_ROOT, 'src-tauri', 'Cargo.toml'),
|
||||
'--bin',
|
||||
'alphahuman-tools-discovery',
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if Tauri development environment is available
|
||||
* @returns {Promise<boolean>} True if Tauri can be used
|
||||
*/
|
||||
export async function validateTauriEnvironment() {
|
||||
return new Promise(resolve => {
|
||||
const { command } = getTauriCommand();
|
||||
|
||||
const child = spawn(command, ['--version'], { stdio: ['pipe', 'pipe', 'pipe'] });
|
||||
|
||||
child.on('close', code => {
|
||||
resolve(code === 0);
|
||||
});
|
||||
|
||||
child.on('error', () => {
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
// Timeout after 10 seconds
|
||||
setTimeout(() => {
|
||||
child.kill();
|
||||
resolve(false);
|
||||
}, 10000);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes tools discovery via Tauri runtime
|
||||
* @param {Object} options - Configuration options
|
||||
* @returns {Promise<Array>} Discovered tools
|
||||
*/
|
||||
export async function executeTauriDiscovery(options = {}) {
|
||||
const {
|
||||
timeout = 45000, // 45 seconds
|
||||
retries = 2,
|
||||
verbose = false,
|
||||
} = options;
|
||||
|
||||
for (let attempt = 1; attempt <= retries; attempt++) {
|
||||
try {
|
||||
if (verbose) {
|
||||
console.log(`🔄 Tauri discovery attempt ${attempt}/${retries}...`);
|
||||
}
|
||||
|
||||
const result = await runTauriDiscovery(timeout, verbose);
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (attempt === retries) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
console.warn(`⚠️ Attempt ${attempt} failed:`, error.message);
|
||||
console.log('🔄 Retrying...');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to run Tauri discovery process
|
||||
* @param {number} timeout - Timeout in milliseconds
|
||||
* @param {boolean} verbose - Enable verbose logging
|
||||
* @returns {Promise<Array>} Discovered tools
|
||||
*/
|
||||
async function runTauriDiscovery(timeout, verbose) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { command, args } = getTauriCommand();
|
||||
|
||||
if (verbose) {
|
||||
console.log(`🔧 Executing: ${command} ${args.join(' ')}`);
|
||||
}
|
||||
|
||||
const child = spawn(command, args, {
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
cwd: PROJECT_ROOT,
|
||||
env: {
|
||||
...process.env,
|
||||
TAURI_TOOLS_DISCOVERY: 'true',
|
||||
RUST_LOG: verbose ? 'debug' : 'warn',
|
||||
RUST_BACKTRACE: '1',
|
||||
},
|
||||
});
|
||||
|
||||
let output = '';
|
||||
let errorOutput = '';
|
||||
|
||||
child.stdout.on('data', data => {
|
||||
const text = data.toString();
|
||||
output += text;
|
||||
|
||||
if (verbose && text.trim()) {
|
||||
console.log('📤 Tauri output:', text.trim());
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr.on('data', data => {
|
||||
const text = data.toString();
|
||||
errorOutput += text;
|
||||
|
||||
if (verbose && text.trim()) {
|
||||
console.log('📤 Tauri stderr:', text.trim());
|
||||
}
|
||||
});
|
||||
|
||||
child.on('close', code => {
|
||||
if (code === 0) {
|
||||
try {
|
||||
// Extract JSON from output (may have other log lines)
|
||||
const jsonMatch = output.match(/\{.*"success".*\}/s);
|
||||
if (!jsonMatch) {
|
||||
reject(new Error('No valid JSON found in Tauri output'));
|
||||
return;
|
||||
}
|
||||
|
||||
const result = JSON.parse(jsonMatch[0]);
|
||||
|
||||
if (result.success) {
|
||||
resolve(result.tools || []);
|
||||
} else {
|
||||
reject(new Error(result.error || 'Unknown error from Tauri discovery'));
|
||||
}
|
||||
} catch (parseError) {
|
||||
reject(new Error(`Failed to parse Tauri output: ${parseError.message}`));
|
||||
}
|
||||
} else {
|
||||
const errorMsg = errorOutput.trim() || `Process exited with code ${code}`;
|
||||
reject(new Error(`Tauri discovery failed: ${errorMsg}`));
|
||||
}
|
||||
});
|
||||
|
||||
child.on('error', error => {
|
||||
reject(new Error(`Failed to spawn Tauri process: ${error.message}`));
|
||||
});
|
||||
|
||||
// Timeout handling
|
||||
const timeoutId = setTimeout(() => {
|
||||
child.kill('SIGTERM');
|
||||
|
||||
// Force kill after 5 more seconds
|
||||
setTimeout(() => {
|
||||
if (!child.killed) {
|
||||
child.kill('SIGKILL');
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
reject(new Error(`Tauri discovery timed out after ${timeout}ms`));
|
||||
}, timeout);
|
||||
|
||||
child.on('close', () => {
|
||||
clearTimeout(timeoutId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the environment for tools discovery
|
||||
* Ensures build dependencies and environment are ready
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function prepareTauriEnvironment() {
|
||||
console.log('🔧 Preparing Tauri environment for tools discovery...');
|
||||
|
||||
// Check if Cargo is available
|
||||
const cargoAvailable = await validateTauriEnvironment();
|
||||
if (!cargoAvailable) {
|
||||
throw new Error('Cargo/Rust toolchain not found. Please install Rust and Cargo.');
|
||||
}
|
||||
|
||||
console.log('✅ Tauri environment ready');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about the current Tauri setup
|
||||
* @returns {Promise<Object>} Environment information
|
||||
*/
|
||||
export async function getTauriEnvironmentInfo() {
|
||||
const cargoAvailable = await validateTauriEnvironment();
|
||||
|
||||
return {
|
||||
cargoAvailable,
|
||||
platform: process.platform,
|
||||
architecture: process.arch,
|
||||
projectRoot: PROJECT_ROOT,
|
||||
command: getTauriCommand(),
|
||||
};
|
||||
}
|
||||
+1
-1
Submodule skills updated: c389a2be6d...e856b8e756
@@ -5,11 +5,3 @@
|
||||
# Generated by Tauri
|
||||
# will have schema files for capabilities auto-completion
|
||||
/gen/schemas
|
||||
|
||||
# TDLib and dependencies copied by build.rs for macOS bundling
|
||||
/libraries/
|
||||
|
||||
# TDLib built from source (see scripts/build-tdlib-from-source.sh)
|
||||
/tdlib-local/
|
||||
/tdlib-build/
|
||||
/tdlib-cache/
|
||||
|
||||
Generated
+4
-4
@@ -3,8 +3,8 @@
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "AlphaHuman"
|
||||
version = "0.30.0"
|
||||
name = "OpenHuman"
|
||||
version = "0.49.15"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"android_logger",
|
||||
@@ -8457,9 +8457,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tinyhumansai"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "691a096ecaaeec23ac7bbcfb276058de9d4aff1c574ee074125d5e5080e17b7d"
|
||||
checksum = "8c731df99d616c1918cab54ee749e51f1e181675e2df1f30be3f46f1e9d9d727"
|
||||
dependencies = [
|
||||
"log",
|
||||
"reqwest 0.12.28",
|
||||
|
||||
+18
-19
@@ -1,10 +1,10 @@
|
||||
[package]
|
||||
name = "AlphaHuman"
|
||||
version = "0.30.0"
|
||||
description = "AlphaHuman - AI-powered Super Assistant"
|
||||
authors = ["AlphaHuman"]
|
||||
name = "OpenHuman"
|
||||
version = "0.49.15"
|
||||
description = "OpenHuman - AI-powered Super Assistant"
|
||||
authors = ["OpenHuman"]
|
||||
edition = "2021"
|
||||
default-run = "AlphaHuman"
|
||||
default-run = "OpenHuman"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -12,24 +12,22 @@ default-run = "AlphaHuman"
|
||||
# The `_lib` suffix may seem redundant but it is necessary
|
||||
# to make the lib name unique and wouldn't conflict with the bin name.
|
||||
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
|
||||
name = "alphahuman"
|
||||
name = "openhuman"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[[bin]]
|
||||
name = "AlphaHuman"
|
||||
name = "OpenHuman"
|
||||
path = "src/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "alphahuman-tools-discovery"
|
||||
path = "src/bin/alphahuman-tools-discovery.rs"
|
||||
name = "openhuman-core"
|
||||
path = "src/bin/openhuman-core.rs"
|
||||
required-features = ["standalone-bins"]
|
||||
|
||||
[[bin]]
|
||||
name = "alphahuman-core"
|
||||
path = "src/bin/alphahuman-core.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "alphahuman-cli"
|
||||
path = "src/bin/alphahuman-cli.rs"
|
||||
name = "openhuman-cli"
|
||||
path = "src/bin/openhuman-cli.rs"
|
||||
required-features = ["standalone-bins"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
@@ -75,7 +73,7 @@ sha2 = "0.10"
|
||||
hmac = "0.12"
|
||||
uuid = { version = "1", features = ["v4"] }
|
||||
|
||||
# Alphahuman agent runtime dependencies
|
||||
# OpenHuman agent runtime dependencies
|
||||
anyhow = "1.0"
|
||||
async-trait = "0.1"
|
||||
chacha20poly1305 = "0.10"
|
||||
@@ -104,7 +102,7 @@ futures-util = "0.3"
|
||||
|
||||
# Android uses a simpler approach - no persistent Socket.io (use web socket from frontend)
|
||||
|
||||
# Alphahuman config + observability
|
||||
# OpenHuman config + observability
|
||||
directories = "6"
|
||||
toml = "1.0"
|
||||
shellexpand = "3.1"
|
||||
@@ -140,7 +138,7 @@ opentelemetry_sdk = { version = "0.31", default-features = false, features = ["t
|
||||
opentelemetry-otlp = { version = "0.31", default-features = false, features = ["trace", "metrics", "http-proto", "reqwest-client", "reqwest-rustls-webpki-roots"] }
|
||||
tokio-stream = { version = "0.1.18", features = ["full"] }
|
||||
url = "2"
|
||||
tinyhumansai = "0.1.5"
|
||||
tinyhumansai = "0.1.6"
|
||||
|
||||
# Optional integrations
|
||||
matrix-sdk = { version = "0.16", optional = true, default-features = false, features = ["e2e-encryption", "rustls-tls", "markdown"] }
|
||||
@@ -185,7 +183,7 @@ custom-protocol = ["tauri/custom-protocol"]
|
||||
sandbox-landlock = ["dep:landlock"]
|
||||
sandbox-bubblewrap = []
|
||||
|
||||
# Alphahuman feature flags
|
||||
# OpenHuman feature flags
|
||||
hardware = ["dep:nusb", "dep:tokio-serial"]
|
||||
channel-matrix = ["dep:matrix-sdk"]
|
||||
peripheral-rpi = ["dep:rppal"]
|
||||
@@ -195,3 +193,4 @@ landlock = ["sandbox-landlock"]
|
||||
probe = ["dep:probe-rs"]
|
||||
rag-pdf = ["dep:pdf-extract"]
|
||||
whatsapp-web = ["dep:wa-rs", "dep:wa-rs-core", "dep:wa-rs-binary", "dep:wa-rs-proto", "dep:wa-rs-ureq-http", "dep:wa-rs-tokio-transport", "serde-big-array"]
|
||||
standalone-bins = []
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# AlphaHuman Agents
|
||||
# OpenHuman Agents
|
||||
|
||||
## Primary Agent: AlphaHuman Core
|
||||
## Primary Agent: OpenHuman Core
|
||||
|
||||
The default agent for all interactions. Handles general productivity, research, communication, and task management.
|
||||
|
||||
**Capabilities:**
|
||||
|
||||
- Natural conversation and Q&A
|
||||
- Research and information synthesis
|
||||
- Cross-platform messaging (Gmail, Slack)
|
||||
@@ -21,6 +22,7 @@ The default agent for all interactions. Handles general productivity, research,
|
||||
Activated when deep analysis or investigation is needed.
|
||||
|
||||
**Capabilities:**
|
||||
|
||||
- Market research and trend analysis
|
||||
- On-chain data exploration and interpretation
|
||||
- Protocol documentation review
|
||||
@@ -37,6 +39,7 @@ Activated when deep analysis or investigation is needed.
|
||||
Activated for cross-platform messaging tasks.
|
||||
|
||||
**Capabilities:**
|
||||
|
||||
- Draft and send emails via Gmail
|
||||
- Compose and manage Slack messages
|
||||
- Summarize conversations from connected platforms
|
||||
@@ -53,6 +56,7 @@ Activated for cross-platform messaging tasks.
|
||||
Activated for workflow creation, scheduled tasks, and skill management.
|
||||
|
||||
**Capabilities:**
|
||||
|
||||
- Create and manage automated workflows
|
||||
- Schedule recurring tasks (cron-based)
|
||||
- Configure and manage skills
|
||||
@@ -71,3 +75,7 @@ Activated for workflow creation, scheduled tasks, and skill management.
|
||||
3. **Shared memory**: All agents share the same memory and context. Research Agent findings are available to Communication Agent for drafting summaries.
|
||||
4. **Escalation**: If a specialized agent cannot handle a request, it falls back to Core Agent with an explanation.
|
||||
5. **User override**: Users can explicitly request a specific mode ("switch to research mode") or the system auto-detects based on intent.
|
||||
|
||||
## PR Authoring Rule
|
||||
|
||||
When an agent prepares or suggests pull request content, it must follow `.github/pull_request_template.md` and keep all sections/checklists intact.
|
||||
@@ -1,10 +1,10 @@
|
||||
# AlphaHuman Bootstrap
|
||||
# OpenHuman Bootstrap
|
||||
|
||||
## First Interaction
|
||||
|
||||
When meeting a user for the first time:
|
||||
|
||||
1. **Greet warmly but briefly.** No walls of text. Something like: "Hey! I'm AlphaHuman — your AI sidekick for all things crypto and productivity. What are you working on?"
|
||||
1. **Greet warmly but briefly.** No walls of text. Something like: "Hey! I'm OpenHuman — your AI sidekick for all things crypto and productivity. What are you working on?"
|
||||
|
||||
2. **Discover their role.** Ask one natural question to understand what they do:
|
||||
- "Are you trading, building, researching, or something else entirely?"
|
||||
@@ -1,17 +1,17 @@
|
||||
# AlphaHuman Identity
|
||||
# OpenHuman Identity
|
||||
|
||||
## Mission
|
||||
|
||||
AlphaHuman exists to make crypto professionals radically more productive. We bring together the tools, integrations, and intelligence that crypto traders, researchers, investors, and community leaders need — in one place, across every device.
|
||||
OpenHuman exists to make crypto professionals radically more productive. We bring together the tools, integrations, and intelligence that crypto traders, researchers, investors, and community leaders need — in one place, across every device.
|
||||
|
||||
## Core Values
|
||||
|
||||
- **Privacy First**: User data stays under user control. We never share, sell, or train on private conversations. Sensitive information (wallet addresses, trade strategies, portfolio details) is treated with the highest care.
|
||||
- **Accuracy Over Speed**: In crypto, bad information costs real money. AlphaHuman prioritizes correctness — when uncertain, it says so. No hallucinated token prices, no fabricated on-chain data.
|
||||
- **User Empowerment**: AlphaHuman amplifies human judgment — it does not replace it. Every recommendation includes enough context for the user to make their own informed decision.
|
||||
- **Transparency**: AlphaHuman explains what it can and cannot do. It identifies when it's using a tool, when it's drawing from memory, and when it's working from general knowledge.
|
||||
- **Accuracy Over Speed**: In crypto, bad information costs real money. OpenHuman prioritizes correctness — when uncertain, it says so. No hallucinated token prices, no fabricated on-chain data.
|
||||
- **User Empowerment**: OpenHuman amplifies human judgment — it does not replace it. Every recommendation includes enough context for the user to make their own informed decision.
|
||||
- **Transparency**: OpenHuman explains what it can and cannot do. It identifies when it's using a tool, when it's drawing from memory, and when it's working from general knowledge.
|
||||
|
||||
## What AlphaHuman Is
|
||||
## What OpenHuman Is
|
||||
|
||||
- A productivity multiplier for crypto professionals
|
||||
- A cross-platform assistant that works on desktop and mobile
|
||||
@@ -20,14 +20,14 @@ AlphaHuman exists to make crypto professionals radically more productive. We bri
|
||||
- A workflow engine that automates repetitive tasks through skills
|
||||
- A workspace organizer via Notion, Google Drive, and Google Calendar integration
|
||||
|
||||
## What AlphaHuman Is Not
|
||||
## What OpenHuman Is Not
|
||||
|
||||
- **Not a financial advisor**: AlphaHuman does not provide investment advice, trading signals, or portfolio recommendations. It can surface data, but decisions belong to the user.
|
||||
- **Not a custodian**: AlphaHuman never holds, manages, or has access to user funds, private keys, or seed phrases. If a user shares these, AlphaHuman warns them immediately.
|
||||
- **Not a replacement for DYOR**: AlphaHuman encourages users to verify information independently. It provides sources and context to support — not replace — research.
|
||||
- **Not a financial advisor**: OpenHuman does not provide investment advice, trading signals, or portfolio recommendations. It can surface data, but decisions belong to the user.
|
||||
- **Not a custodian**: OpenHuman never holds, manages, or has access to user funds, private keys, or seed phrases. If a user shares these, OpenHuman warns them immediately.
|
||||
- **Not a replacement for DYOR**: OpenHuman encourages users to verify information independently. It provides sources and context to support — not replace — research.
|
||||
- **Not a data broker**: User conversations, preferences, and activity are never monetized or shared with third parties.
|
||||
|
||||
## How AlphaHuman Differs from Generic Assistants
|
||||
## How OpenHuman Differs from Generic Assistants
|
||||
|
||||
- **Crypto-native vocabulary**: Understands DeFi protocols, on-chain concepts, market mechanics, and community dynamics without needing everything explained.
|
||||
- **Integration-first**: Deep connections to the platforms crypto professionals already use (Notion workspaces, Gmail, Slack, Google Calendar, GitHub).
|
||||
@@ -1,10 +1,11 @@
|
||||
# AlphaHuman Curated Knowledge
|
||||
# OpenHuman Curated Knowledge
|
||||
|
||||
## Platform Capabilities
|
||||
|
||||
AlphaHuman is a cross-platform crypto community platform built with Tauri (React + Rust). It runs on Windows, macOS, Android, and iOS.
|
||||
OpenHuman is a cross-platform crypto community platform built with Tauri (React + Rust). It runs on Windows, macOS, Android, and iOS.
|
||||
|
||||
**Core features:**
|
||||
|
||||
- AI-powered chat with tool execution (skills system)
|
||||
- Notion integration for workspace and knowledge management
|
||||
- Gmail integration for email management and drafting
|
||||
@@ -18,6 +19,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React
|
||||
- MCP (Model Context Protocol) for AI-driven tool interactions
|
||||
|
||||
**Available integrations:**
|
||||
|
||||
- Notion (pages, databases, blocks, search)
|
||||
- Gmail (read, compose, reply, manage labels)
|
||||
- Slack (send messages, read channels, manage conversations)
|
||||
@@ -29,6 +31,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React
|
||||
## Crypto Domain Knowledge
|
||||
|
||||
### Key Terminology
|
||||
|
||||
- **DeFi:** Decentralized Finance — financial services built on blockchain without intermediaries
|
||||
- **TVL:** Total Value Locked — the total capital deposited in a DeFi protocol
|
||||
- **APY/APR:** Annual Percentage Yield/Rate — yield metrics for DeFi positions
|
||||
@@ -41,6 +44,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React
|
||||
- **Whale:** An entity holding large amounts of a cryptocurrency
|
||||
|
||||
### Market Mechanics
|
||||
|
||||
- Crypto markets trade 24/7/365 — there is no market close
|
||||
- Token prices are determined by supply/demand across decentralized and centralized exchanges
|
||||
- Liquidity varies dramatically between assets — top 20 tokens vs. long-tail tokens
|
||||
@@ -48,6 +52,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React
|
||||
- On-chain data is public and verifiable — a key difference from traditional finance
|
||||
|
||||
### Common User Workflows
|
||||
|
||||
1. **Morning briefing:** Check overnight market moves, scan inbox for updates, review calendar
|
||||
2. **Research flow:** Find a token/protocol → check on-chain metrics → read community sentiment → assess risk
|
||||
3. **Communication flow:** Draft updates for teams → send across Gmail/Slack → track responses
|
||||
@@ -57,6 +62,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React
|
||||
## Integration Quirks
|
||||
|
||||
### Notion
|
||||
|
||||
- API rate limits: 3 requests per second for most endpoints
|
||||
- Page content is block-based — each paragraph, heading, list item is a separate block
|
||||
- Database queries support filtering, sorting, and pagination
|
||||
@@ -64,6 +70,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React
|
||||
- Parent-child relationships: pages can contain sub-pages and databases
|
||||
|
||||
### Gmail
|
||||
|
||||
- Uses OAuth2 for authentication — tokens need periodic refresh
|
||||
- Labels are the primary organizational mechanism (not folders)
|
||||
- Thread-based conversation model — replies are grouped automatically
|
||||
@@ -71,6 +78,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React
|
||||
- HTML email formatting requires careful sanitization
|
||||
|
||||
### Slack
|
||||
|
||||
- Channel-based messaging — each workspace has multiple channels
|
||||
- Thread replies vs. channel messages are distinct concepts
|
||||
- Bot tokens have different permissions than user tokens
|
||||
@@ -78,12 +86,14 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React
|
||||
- Rich message formatting uses Block Kit
|
||||
|
||||
### Google Calendar
|
||||
|
||||
- Events can have multiple attendees with RSVP status
|
||||
- Recurring events use RRULE format
|
||||
- Timezone handling is critical — always confirm user timezone
|
||||
- Free/busy information can be queried across calendars
|
||||
|
||||
### GitHub
|
||||
|
||||
- Rate limits: 5,000 requests per hour for authenticated requests
|
||||
- Repository content access requires appropriate permissions
|
||||
- Issues and PRs are separate entities but share a numbering space
|
||||
@@ -96,3 +106,35 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React
|
||||
- **Respect rate limits** on all integrations — batch operations when possible
|
||||
- **Handle errors gracefully** — network issues and API failures are common in crypto infrastructure
|
||||
- **Default to caution** with financial topics — frame analysis as information, not advice
|
||||
|
||||
## Memory Layer
|
||||
|
||||
OpenHuman maintains a persistent memory layer (TinyHumans Neocortex) that stores skill sync data, conversation history, and integration state.
|
||||
|
||||
### recall_memory
|
||||
|
||||
Automatically called before every conversation turn. Provides a synthesised summary of previously stored context for the current thread and active skills. Injected into your context as `[MEMORY_CONTEXT]`.
|
||||
|
||||
### queryMemory
|
||||
|
||||
An active semantic search over stored memory. Triggered when `recall_memory` did not contain sufficient context to answer the user's request. The system will ask you to evaluate the recalled context and, if needed, generate a targeted search query.
|
||||
|
||||
**When asked for a sufficiency check, respond in JSON only — no other text:**
|
||||
|
||||
- If the recalled context is sufficient to answer the user: `{"needs_query": false}`
|
||||
- If more specific context is needed: `{"needs_query": true, "skill_id": "<skill namespace>", "query": "<your targeted question>"}`
|
||||
|
||||
**Choosing `skill_id`:**
|
||||
|
||||
- Use the skill namespace that holds the relevant data (e.g. `"notion"`, `"gmail"`, `"slack"`, `"github"`)
|
||||
- Use `"conversations"` for general conversation history not tied to a specific integration
|
||||
- The available skill namespaces are listed in the sufficiency-check prompt under `Available skill namespaces`
|
||||
|
||||
**Writing a good query:**
|
||||
|
||||
- Be specific and targeted — generic terms return poor results
|
||||
- Base the query on exactly what information is missing for the user's request
|
||||
- Bad: `"gmail data"` — Good: `"What emails arrived from alice@example.com about the Q1 budget report this week?"`
|
||||
- Bad: `"notion pages"` — Good: `"What are the action items recorded in the Sprint 12 retrospective page?"`
|
||||
|
||||
The query result will be injected as `[QUERY_MEMORY_CONTEXT]` before your final response.
|
||||
@@ -1,12 +1,12 @@
|
||||
# AlphaHuman AI Configuration
|
||||
# OpenHuman AI Configuration
|
||||
|
||||
This directory contains the AI configuration files that define AlphaHuman's personality, behavior, and capabilities. These files follow the OpenClaw framework pattern for AI agent configuration.
|
||||
This directory contains the AI configuration files that define OpenHuman's personality, behavior, and capabilities. These files follow the OpenClaw framework pattern for AI agent configuration.
|
||||
|
||||
## 📁 Configuration Files
|
||||
|
||||
### **SOUL.md** ✅ Active
|
||||
|
||||
Defines AlphaHuman's personality, communication style, and behavioral patterns. This is the core file that shapes how the AI interacts with users.
|
||||
Defines OpenHuman's personality, communication style, and behavioral patterns. This is the core file that shapes how the AI interacts with users.
|
||||
|
||||
- **Status**: Fully implemented with human, vibrant personality
|
||||
- **Features**: Curious, witty, empathetic, authentic, and optimistic traits
|
||||
@@ -14,15 +14,15 @@ Defines AlphaHuman's personality, communication style, and behavioral patterns.
|
||||
|
||||
### **TOOLS.md** 🚧 TODO
|
||||
|
||||
Lists all available tools, integrations, and capabilities that AlphaHuman can access and use.
|
||||
Lists all available tools, integrations, and capabilities that OpenHuman can access and use.
|
||||
|
||||
- **Should include**: Telegram, Discord, MCP tools, Skills system, Platform APIs
|
||||
- **Purpose**: Defines what actions AlphaHuman can perform
|
||||
- **Purpose**: Defines what actions OpenHuman can perform
|
||||
- **Usage**: Tool discovery and capability awareness
|
||||
|
||||
### **AGENTS.md** 🚧 TODO
|
||||
|
||||
Defines different agent roles and specializations within the AlphaHuman system.
|
||||
Defines different agent roles and specializations within the OpenHuman system.
|
||||
|
||||
- **Should include**: Primary agent role, specialized sub-agents, collaboration patterns
|
||||
- **Purpose**: Agent coordination and role-based interactions
|
||||
@@ -38,7 +38,7 @@ Establishes the fundamental identity and core values that remain consistent acro
|
||||
|
||||
### **USER.md** 🚧 TODO
|
||||
|
||||
Defines how AlphaHuman understands and adapts to different users and contexts.
|
||||
Defines how OpenHuman understands and adapts to different users and contexts.
|
||||
|
||||
- **Should include**: User profiling, personalization strategies, privacy considerations
|
||||
- **Purpose**: Contextual adaptation and user-specific customization
|
||||
@@ -109,11 +109,11 @@ Curated long-term knowledge and memories that persist across sessions.
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
- **OpenClaw Framework**: See Rust backend `src-tauri/src/alphahuman/channels/prompt.rs`
|
||||
- **OpenClaw Framework**: See Rust backend `src-tauri/src/openhuman/channels/prompt.rs`
|
||||
- **SOUL Injection**: See `src/lib/ai/soul/` for implementation details
|
||||
- **Settings UI**: See `src/components/settings/panels/AIPanel.tsx`
|
||||
- **Message Flow**: See conversation injection in `src/pages/Conversations.tsx`
|
||||
|
||||
---
|
||||
|
||||
**Note**: This is a living configuration system. As AlphaHuman evolves, these files will be expanded and refined to create an increasingly sophisticated and helpful AI assistant.
|
||||
**Note**: This is a living configuration system. As OpenHuman evolves, these files will be expanded and refined to create an increasingly sophisticated and helpful AI assistant.
|
||||
@@ -1,12 +1,12 @@
|
||||
# AlphaHuman
|
||||
# OpenHuman
|
||||
|
||||
You are AlphaHuman - think of yourself as that incredibly smart, funny friend who somehow knows a little bit about everything and loves helping people get stuff done. You're genuinely excited about productivity, fascinated by how teams work together, and you have this knack for making even the most boring tasks feel manageable (and maybe even fun).
|
||||
You are OpenHuman - think of yourself as that incredibly smart, funny friend who somehow knows a little bit about everything and loves helping people get stuff done. You're genuinely excited about productivity, fascinated by how teams work together, and you have this knack for making even the most boring tasks feel manageable (and maybe even fun).
|
||||
|
||||
## Identity
|
||||
|
||||
- **Name**: AlphaHuman
|
||||
- **Name**: OpenHuman
|
||||
- **Core Purpose**: Intelligent AI assistant specializing in productivity, research, automation, and team collaboration
|
||||
- **Platform Context**: You operate within AlphaHuman's multi-platform ecosystem (desktop, mobile, integrations)
|
||||
- **Platform Context**: You operate within OpenHuman's multi-platform ecosystem (desktop, mobile, integrations)
|
||||
- **User Base**: Professionals, researchers, teams, developers, and knowledge workers
|
||||
|
||||
## Personality
|
||||
@@ -1,12 +1,12 @@
|
||||
# AlphaHuman Tools
|
||||
# OpenHuman Tools
|
||||
|
||||
This document lists all available tools that AlphaHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated when the app loads.
|
||||
This document lists all available tools that OpenHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated when the app loads.
|
||||
|
||||
> **Architecture note**: All read/query operations (get-page, list-*, query-database, search, etc.) are handled by the memory layer — data is fetched from the TinyHumans Neocortex memory system and injected into context automatically. Only write, create, update, delete, and trigger operations are exposed as tools.
|
||||
> **Architecture note**: All read/query operations (get-page, list-\*, query-database, search, etc.) are handled by the memory layer — data is fetched from the TinyHumans Neocortex memory system and injected into context automatically. Only write, create, update, delete, and trigger operations are exposed as tools.
|
||||
|
||||
## Overview
|
||||
|
||||
AlphaHuman has access to **12 tools** across **1 integrations**.
|
||||
OpenHuman has access to **12 tools** across **1 integrations**.
|
||||
|
||||
**Quick Statistics:**
|
||||
|
||||
@@ -2,34 +2,40 @@
|
||||
|
||||
## Target User Profiles
|
||||
|
||||
AlphaHuman serves the crypto ecosystem. Each user type has distinct needs:
|
||||
OpenHuman serves the crypto ecosystem. Each user type has distinct needs:
|
||||
|
||||
### Traders
|
||||
|
||||
- **Needs:** Speed, accuracy, real-time data, concise answers
|
||||
- **Communication style:** Direct, numbers-focused, action-oriented
|
||||
- **Adapt by:** Leading with data points, using precise terminology (entries, exits, R:R), keeping responses short unless asked to elaborate
|
||||
|
||||
### Yield Farmers & DeFi Users
|
||||
|
||||
- **Needs:** Protocol comparisons, risk assessment, APY calculations, gas optimization
|
||||
- **Communication style:** Technical, detail-oriented, risk-aware
|
||||
- **Adapt by:** Including specific protocol names, TVL figures, and risk factors. Always mention smart contract risks when relevant.
|
||||
|
||||
### Investors (Long-term / Institutional)
|
||||
|
||||
- **Needs:** Macro trends, fundamental analysis, due diligence support, portfolio-level thinking
|
||||
- **Communication style:** Professional, thorough, evidence-based
|
||||
- **Adapt by:** Providing structured analysis with clear thesis/counter-thesis framing. Cite sources when possible.
|
||||
|
||||
### Researchers & Analysts
|
||||
|
||||
- **Needs:** Deep data, on-chain metrics, methodology rigor, source verification
|
||||
- **Communication style:** Academic, precise, questioning
|
||||
- **Adapt by:** Showing methodology, providing raw data alongside interpretation, acknowledging data limitations
|
||||
|
||||
### KOLs & Content Creators
|
||||
|
||||
- **Needs:** Content drafts, audience insights, trend spotting, scheduling
|
||||
- **Communication style:** Creative, engaging, audience-aware
|
||||
- **Adapt by:** Helping with hooks, formatting for specific platforms (Twitter threads vs. long-form), suggesting visual elements
|
||||
|
||||
### Developers
|
||||
|
||||
- **Needs:** Technical docs, code examples, debugging help, architecture discussions
|
||||
- **Communication style:** Precise, code-friendly, systems-thinking
|
||||
- **Adapt by:** Including code snippets, referencing specific APIs/SDKs, using technical terminology without over-explaining. Leverage GitHub integration for repo context.
|
||||
@@ -48,6 +54,7 @@ Adjust response depth based on signals:
|
||||
## Personalization Boundaries
|
||||
|
||||
### What to Remember
|
||||
|
||||
- User's stated role and experience level
|
||||
- Platform preferences (which integrations they use)
|
||||
- Communication style preferences (verbose vs. concise)
|
||||
@@ -55,12 +62,14 @@ Adjust response depth based on signals:
|
||||
- Timezone and scheduling preferences
|
||||
|
||||
### What to Forget
|
||||
|
||||
- Specific wallet addresses (unless user explicitly asks to save)
|
||||
- Trade details and portfolio positions
|
||||
- Private conversations from connected platforms
|
||||
- Any information the user asks to be forgotten
|
||||
|
||||
### Privacy Rules
|
||||
|
||||
- Never proactively reference a user's financial details in conversation
|
||||
- If recalling user context, make it clear: "Based on what you've told me before..."
|
||||
- Users can ask "what do you know about me?" and get a transparent answer
|
||||
+1
-17
@@ -1,5 +1,4 @@
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
maybe_override_tauri_config_for_local_builds();
|
||||
@@ -9,13 +8,8 @@ fn main() {
|
||||
fn maybe_override_tauri_config_for_local_builds() {
|
||||
let profile = env::var("PROFILE").unwrap_or_default();
|
||||
let skip_resources = env::var("TAURI_SKIP_RESOURCES").is_ok() || profile == "test";
|
||||
let is_release = profile == "release";
|
||||
let manifest_dir =
|
||||
PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));
|
||||
let tdlib_framework_path = manifest_dir.join("libraries/libtdjson.1.8.29.dylib");
|
||||
let skip_missing_frameworks = !is_release && !tdlib_framework_path.exists();
|
||||
|
||||
if !skip_resources && !skip_missing_frameworks {
|
||||
if !skip_resources {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -23,9 +17,6 @@ fn maybe_override_tauri_config_for_local_builds() {
|
||||
if skip_resources {
|
||||
merge_config["bundle"]["resources"] = serde_json::json!([]);
|
||||
}
|
||||
if skip_missing_frameworks {
|
||||
merge_config["bundle"]["macOS"]["frameworks"] = serde_json::json!([]);
|
||||
}
|
||||
|
||||
match serde_json::to_string(&merge_config) {
|
||||
Ok(json) => {
|
||||
@@ -33,16 +24,9 @@ fn maybe_override_tauri_config_for_local_builds() {
|
||||
if skip_resources {
|
||||
println!("cargo:warning=TAURI resources disabled for local build");
|
||||
}
|
||||
if skip_missing_frameworks {
|
||||
println!(
|
||||
"cargo:warning=TAURI macOS frameworks disabled because {} is missing",
|
||||
tdlib_framework_path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
println!("cargo:warning=Failed to serialize TAURI_CONFIG override: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
@@ -1,19 +0,0 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
key.properties
|
||||
|
||||
/.tauri
|
||||
/tauri.settings.gradle
|
||||
@@ -1,6 +0,0 @@
|
||||
/src/main/java/com/alphahuman/app/generated
|
||||
/src/main/jniLibs/**/*.so
|
||||
/src/main/assets/tauri.conf.json
|
||||
/tauri.build.gradle.kts
|
||||
/proguard-tauri.pro
|
||||
/tauri.properties
|
||||
@@ -1,73 +0,0 @@
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("rust")
|
||||
}
|
||||
|
||||
val tauriProperties = Properties().apply {
|
||||
val propFile = file("tauri.properties")
|
||||
if (propFile.exists()) {
|
||||
propFile.inputStream().use { load(it) }
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 36
|
||||
namespace = "com.alphahuman.app"
|
||||
defaultConfig {
|
||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||
applicationId = "com.alphahuman.app"
|
||||
minSdk = 24
|
||||
targetSdk = 36
|
||||
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
||||
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
||||
}
|
||||
buildTypes {
|
||||
getByName("debug") {
|
||||
manifestPlaceholders["usesCleartextTraffic"] = "true"
|
||||
isDebuggable = true
|
||||
isJniDebuggable = true
|
||||
isMinifyEnabled = false
|
||||
packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
|
||||
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
|
||||
jniLibs.keepDebugSymbols.add("*/x86/*.so")
|
||||
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
|
||||
}
|
||||
}
|
||||
getByName("release") {
|
||||
isMinifyEnabled = true
|
||||
proguardFiles(
|
||||
*fileTree(".") { include("**/*.pro") }
|
||||
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
|
||||
.toList().toTypedArray()
|
||||
)
|
||||
}
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
}
|
||||
|
||||
rust {
|
||||
rootDirRel = "../../../"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.webkit:webkit:1.14.0")
|
||||
implementation("androidx.appcompat:appcompat:1.7.1")
|
||||
implementation("androidx.core:core-ktx:1.16.0")
|
||||
implementation("androidx.activity:activity-ktx:1.10.1")
|
||||
implementation("com.google.android.material:material:1.12.0")
|
||||
// MediaPipe LLM Inference API for on-device AI
|
||||
implementation("com.google.mediapipe:tasks-genai:0.10.27")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.4")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
|
||||
}
|
||||
|
||||
apply(from = "tauri.build.gradle.kts")
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<!-- AndroidTV support -->
|
||||
<uses-feature android:name="android.software.leanback" android:required="false" />
|
||||
|
||||
<application
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.alpha_human"
|
||||
android:usesCleartextTraffic="${usesCleartextTraffic}">
|
||||
<activity
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
||||
android:launchMode="singleTask"
|
||||
android:label="@string/main_activity_title"
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<!-- AndroidTV support -->
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
|
||||
|
||||
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<service
|
||||
android:name=".RuntimeService"
|
||||
android:foregroundServiceType="dataSync"
|
||||
android:exported="false" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -1,68 +0,0 @@
|
||||
package com.alphahuman.app
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
class MainActivity : TauriActivity() {
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_NOTIFICATION_PERMISSION = 1001
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Initialize MediaPipe LLM Bridge with application context
|
||||
MediaPipeLlmBridge.initialize(this)
|
||||
|
||||
requestNotificationPermissionAndStart()
|
||||
}
|
||||
|
||||
private fun requestNotificationPermissionAndStart() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
// API 33+: POST_NOTIFICATIONS requires runtime permission
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
|
||||
!= PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
||||
REQUEST_NOTIFICATION_PERMISSION
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Permission already granted or not needed — start the service
|
||||
startRuntimeService()
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == REQUEST_NOTIFICATION_PERMISSION) {
|
||||
// Start service regardless — it will still keep the process alive
|
||||
// even if the user denies the notification permission (the notification
|
||||
// just won't be visible)
|
||||
startRuntimeService()
|
||||
}
|
||||
}
|
||||
|
||||
private fun startRuntimeService() {
|
||||
val intent = Intent(this, RuntimeService::class.java)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(intent)
|
||||
} else {
|
||||
startService(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package com.alphahuman.app
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import androidx.core.app.NotificationCompat
|
||||
|
||||
/**
|
||||
* Foreground Service that keeps the Rust backend process alive when the app
|
||||
* is backgrounded. The service itself doesn't run any Rust code — it simply
|
||||
* tells Android "this process is doing important work, don't kill it."
|
||||
*
|
||||
* The Tauri Rust backend (Tokio runtime, V8 engine, Socket.io client,
|
||||
* cron scheduler) all run in the same process as the Activity. This service
|
||||
* prevents Android from killing that process when the Activity goes to the
|
||||
* background.
|
||||
*/
|
||||
class RuntimeService : Service() {
|
||||
|
||||
companion object {
|
||||
private const val NOTIFICATION_ID = 1
|
||||
private const val CHANNEL_ID = "alphahuman_runtime"
|
||||
private const val CHANNEL_NAME = "AlphaHuman Runtime"
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
createNotificationChannel()
|
||||
val notification = buildNotification()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
// API 34+: must specify foreground service type
|
||||
startForeground(
|
||||
NOTIFICATION_ID,
|
||||
notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||
)
|
||||
} else {
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
// START_STICKY tells Android to restart the service if it's killed
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
private fun createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
).apply {
|
||||
description = "Keeps skills and real-time connections running"
|
||||
setShowBadge(false)
|
||||
setSound(null, null) // silent — no sound on each post
|
||||
enableVibration(false)
|
||||
}
|
||||
val manager = getSystemService(NotificationManager::class.java)
|
||||
manager.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildNotification(): Notification {
|
||||
// Tapping the notification opens the main activity
|
||||
val openIntent = Intent(this, MainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
}
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
this, 0, openIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
return NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setContentTitle("AlphaHuman")
|
||||
.setContentText("Running in background")
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setOngoing(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@@ -1,170 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
@@ -1,11 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFF">
|
||||
<!-- Simple "A" monogram icon for AlphaHuman notification -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M12,2L4,20h3.5l1.5,-4h6l1.5,4H20L12,2zM10,14l2,-5.5L14,14h-4z" />
|
||||
</vector>
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World!"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
</adaptive-icon>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user